A vida é um labirinto: tomamos o caminho errado antes de aprendermos a andar


30

Entrada:

Um labirinto contendo os caracteres:

  • -- (parede horizontal);
  • | (parede vertical);
  • + (conexão);
  • (espaço para caminhar);
  • I (Entrada);
  • U (Saída).

Ou seja, uma entrada pode ser assim:

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

Saída:

O mais eficiente caminho que deve andar para começar a partir da entrada para a saída do labirinto (através do labirinto), indicado pelos caracteres indicando esquerda, direita, para cima e para baixo (ou seja >; <; ^; v).

Regras do desafio:

  • Você pode receber a entrada em qualquer formato razoável. String-array, String única com novas linhas, conjunto de caracteres 2D, etc. são todos os formatos de entrada possíveis.
  • A saída pode consistir em quatro caracteres distintos. Ou seja ><^v; →←↑↓; ⇒⇐⇑⇓; RLUD; 0123; ABCD; etc.)
  • Você tem permissão para adicionar espaços ou novas linhas à saída, se preferir; isso é opcional.
  • Os passos são contados por quadrado (veja quatro +símbolos para os quadrados) e não por caractere.
  • O labirinto pode ser do tamanho de 5x5 a 15x15 e sempre será um quadrado (portanto, não haverá casos de teste para labirintos 5x10).
  • Você pode assumir que todo labirinto possui um ou mais caminhos válidos do início ao fim e sempre gera o menor (consulte os casos de teste 4 e 5).
  • Se houver vários caminhos com o mesmo comprimento, você poderá escolher qual deles enviar (consulte o caso de teste 6).
  • Você não pode 'andar' fora dos limites do labirinto (consulte os casos de teste 7 e 8).

Regras gerais:

  • Isso é , então a resposta mais curta em bytes vence.
    Não permita que idiomas com código de golfe o desencorajem a postar respostas com idiomas que não sejam codegolf. Tente encontrar uma resposta o mais curta possível para 'qualquer' linguagem de programação.
  • As regras padrão se aplicam à sua resposta, para que você possa usar STDIN / STDOUT, funções / método com os parâmetros adequados, programas completos. Sua chamada.
  • As brechas padrão são proibidas.
  • Se possível, adicione um link com um teste para o seu código.
  • Além disso, adicione uma explicação, se necessário.

Casos de teste:

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<

Labirintos gerados usando esta ferramenta (e em alguns casos ligeiramente modificados).


10
Encontrei uma solução mais curta para o terceiro caso de teste! v<<<<<<^^^^^(sempre pensar fora da caixa)
— Leo

2
Se alguém puder provar que seu código produzirá a solução mais curta, com tempo e memória suficientes, ele concorre? Mesmo no caso de um tempo de execução realmente longo (moda do fim do universo)?
— Yytsi 8/02

1
@JackBates É uma piada. Ele literalmente contorna a caixa até a saída: D
— Yytsi 8/17

1
Eu acho que o primeiro caso de teste está errado, deveria estar >v>>>vv<v>>v>v>>vvv>>>.
— SMLS

1
@KevinCruijssen Por exemplo, uma solução que testa cada combinação de "v ^ <>" para um comprimento até a quantidade de caixas vazias dentro do labirinto. A solução certa estará lá, mas leva tempo astronômico para calcular.
— Yytsi

Respostas:


7

Retina , 338 281 275 273 261 bytes

¶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|&

Experimente online!


Notas

  • Devido a espaços em branco significativos, todos os espaços (0x20 ) são substituídos por interpunct ( ·) nesta resposta e no link TIO. O programa funciona bem se os espaços forem restaurados.
  • Usa AvKrpara cima, baixo, esquerda e direita, respectivamente. Esses podem ser substituídos por quaisquer letras, excetoI .
  • Leva cerca de 40s no TIO para o caso de teste 15 × 15. Seja paciente.Retrabalhou a peça para encontrar o caminho mais curto assim que o caminho chegou à saída. Acontece que estava demorando muito tempo.
  • Pode quebrar completamente em labirintos com 66 ou mais células de largura, mas que podem lidar com labirintos de altura arbitrária. Uma correção para largura arbitrária leva +1 byte.

Explicação

O programa consiste em 3 fases:

  • UMA fase de construção para converter o labirinto em um formato compacto mais fácil de trabalhar (detalhado abaixo).
  • Uma fase de preenchimento para resolver o labirinto usando um algoritmo de preenchimento.
  • Uma fase de retorno para retornar o caminho mais curto na saída.

Formato

Como o formato do labirinto original é bastante pesado, a primeira parte do programa o converte em um formato diferente.

Células

No formato original, cada célula é representada como uma região 2 × 3:

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

Como a coluna da direita não contém informações, o programa identifica células como qualquer região 2 × 2 com um + na parte superior esquerda.

Isso nos deixa com 3 tipos de células:

  • Células I : Células que estão corretamente dentro do labirinto.
  • Células R : Células que estão à direita do labirinto. Eles são criados pelo preenchimento usado para abrigar a entrada ou a saída. Por exemplo, a saídaU no caso de teste 1 está em uma célula R.
  • Células B : Células que estão abaixo do labirinto. Como as células R, elas são criadas por preenchimento.

No novo formato, as células são representadas como uma sequência de comprimento variável:

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

As paredes esquerda e superior são copiadas do formato original. O número da coluna é baseado na posição horizontal da célula e é usado para alinhamento (identificação de células diretamente em cima / abaixo uma da outra). Caminho é uma sequência alfabética usada durante a fase de preenchimento para salvar o caminho mais curto para alcançar essa célula. O marcador de caminho e saída será mais explicado.

Meias células

Embora a maioria do labirinto seja de células, existem regiões do labirinto que não são células:

  • R Meias células : se não houver preenchimento correto, o+ s ao longo da parede direita não formarão células, pois estão na última coluna.
  • L Meias células : se houver preenchimento à esquerda, as células não poderão se formar, pois não haverá +à esquerda delas. Por exemplo, a entrada Ino caso de teste 1 está em uma meia célula L.

Tecnicamente, existem meias células T acima do labirinto (quando há preenchimento superior) e meias células B (ao longo da parede inferior quando não há preenchimento inferior), mas elas não são representadas no novo formato.

A linha superior de uma meia célula seria removida como parte da construção de células completas na mesma linha, para que as meias células sejam representadas no novo formato como

<wall/exit marker>? <path>

An meias células é apenas |. An L Meia célula tem apenas Io caminho, apenas o marcador de saída e um caminho vazio, ou apenas uma parede vazia.

Entradas e saídas

Se a entrada estiver à esquerda, direita ou parte inferior do labirinto, o marcador de entrada Iseria naturalmente incluído na (meia) célula como o caminho, que pode ser removido ao retornar o caminho final.

Se a entrada estiver acima do labirinto, o primeiro passo (para baixo) é dado durante a fase de construção, pois as meias células T são removidas durante a construção. Isso mantém um caminho viável em uma célula cheia. A parede superior é fechada depois.

Se a saída for para a esquerda, direita ou parte inferior do labirinto, então Useria naturalmente incluída na (meia) célula. Para evitar ser confundido com um caminho, o marcador de saída não alfanumérico &é usado em vez de U. O marcador de saída é incorporado em uma célula ou meia célula (conforme especificado acima).

Se a saída estiver acima do labirinto, seria o único buraco que pode ir acima da linha superior das células (já que o da entrada, se presente, já estaria fechado). Qualquer caminho que alcance esse buraco pode sair do labirinto dando um passo para cima.

Por fim, qualquer célula B que contenha a entrada ou a saída deve fechar a parede esquerda para evitar "resolver" o labirinto caminhando pelas células B. Entradas e saídas em Células R ou L Meia-célula não precisam de processamento adicional, pois o algoritmo de preenchimento não permite movimentos verticais de / para elas.

Exemplo

Como exemplo, o primeiro caso de teste

·+--+--+--+--+--+--+--+--+--+--+·
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&

no novo formato. Você pode converter outros labirintos aqui .


Fase de construção

A fase de construção compõe as 13 primeiras linhas do programa.

¶U
¶&

Converte a saída em L Meia célula para sair do marcador

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

Adiciona paredes à esquerda da entrada e saída nas células B

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

Dá o primeiro passo se a entrada estiver acima do labirinto

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

Executa a conversão real

·v
-v

Fecha o orifício de entrada superior

G`1

Mantém apenas linhas com a 1. Como os labirintos têm pelo menos 5 células de largura e o número de colunas ocorre em incrementos de 3, uma linha com células de novo formato deve conter um número de coluna entre 10 e 19.

·U
&

Converte a saída na célula R ou na célula B para sair do marcador


Fase de preenchimento

A fase de preenchimento compõe as próximas 8 linhas do programa. Ele usa um algoritmo de preenchimento de inundação para preencher todas as células com o caminho mais curto a ser alcançado a partir da entrada.

{`

Coloca toda a fase de preenchimento em um loop para preencher todo o labirinto.

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

Cada célula capaz de se mover para a esquerda o faz. Uma célula é capaz de se mover para a esquerda se

  1. tem um caminho não vazio
  2. tem uma parede esquerda vazia; e
  3. a célula ou meia célula L à sua esquerda tem um caminho vazio
(\w+)·\d+.\B
$&$1r

Então, cada célula capaz de se mover para a direita o faz. Uma célula é capaz de se mover para a direita se

  1. tem um caminho não vazio
  2. a célula à sua direita tem uma parede esquerda vazia; e
  3. a célula à direita tem um caminho vazio
(?<=\D\2.(\w+).+?¶.*\D(\d+)[·&])\B
$1v

Então, cada célula capaz de se mover para baixo o faz. Uma célula é capaz de descer se

  1. tem um caminho não vazio
  2. tem pelo menos uma célula ou meia célula à sua direita (ou seja, não é uma célula R)
  3. a célula abaixo dela (ou seja, a célula na próxima linha com o mesmo número de coluna) tem uma parede superior vazia ou o marcador de saída; e
  4. a célula abaixo dela tem um caminho vazio

Observe que L meias-células não podem se mover para baixo, pois não possuem números de coluna.

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

Então, cada célula capaz de subir faz isso. Uma célula é capaz de subir se

  1. tem um caminho não vazio
  2. tem uma parede superior vazia
  3. a célula acima dela tem pelo menos uma célula ou meia célula à sua direita; e
  4. a célula acima dela tem um caminho vazio

Fase de retorno

A fase de retorno compõe as últimas 5 linhas do programa. Essa fase procura e retorna o caminho preenchido na célula de saída.

O padrão do caminho na saída depende de onde a saída está:

  1. Se a saída estiver em uma meia célula L, essa meia célula seria & <path>
  2. Se a saída estiver em uma célula R ou célula B, essa célula seria <left wall> <column number> & <path>
  3. Se a saída estiver em uma meia célula T, como observado acima, a célula I que leva à saída estará <left wall> <column number> · <path>na linha superior.
^.+\d·(\w+)
&$1A

Localiza uma célula na linha superior com uma parede superior vazia e um caminho não vazio. Isso cuida do último caso, adicionando o último passo e o marcador de saída.

M!`&\w+

Corresponde e retorna um caminho não vazio após um marcador de saída.

I|&

Remove o marcador de saída e o Iprefixo do caminho.


Por que o AvKr? Eles têm um significado / são abreviações para cima, baixo, esquerda e direita no seu idioma nativo ou há outro motivo para você escolher esses caracteres específicos?
— Kevin Cruijssen

@KevinCruijssen Simplesmente porque preciso usar caracteres alfanuméricos e AvKrser a coisa mais próxima das setas no alfano.
— TwiNight 5/07

12

Perl 6 , 259 295 bytes

{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...*]}

Como funciona

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

Isso comprime o labirinto para que o interior de cada célula seja 1x1 em vez de caracteres de espaço 2x1:

 + - + - + - + - + - + + - + - + - + - + - + 
Eu | | Eu | |
 + + - + - + + + + + - + - + + + 
 | | | | | | | |
 + + - + + + + + + - + + + + 
 | | | | | -> | | | | |
 + + + - + + + + + + - + + + 
 | | | | | |
 + - + + + - + - + + - + + + - + - + 
 | | U | você
 + - + - + - + - + - + + - + - + - + - + - +

  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/
        }
    }

Esta é a função de busca de caminho recursiva. São necessários três parâmetros: a coordenada atual c=(y,x), a lista de coordenadas já visitadas ve o caminho ppercorrido até o momento (como uma lista de caracteres de seta).

Se o caractere na coordenada atual for um espaço, ele retornará aos quatro vizinhos.
Se o personagem na coordenada atual é a I, ele se repete para os dois vizinhos que não estão "ao longo da borda", forçando soluções a percorrer o labirinto e não em torno dele.
Se o caractere na coordenada atual for a U, ele chamará takea cadeia de caminho acumulada.

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

A função recursiva é chamada inicialmente com a coordenada da letra I, encontrada usando um regex.

A gatherpalavra-chave coleta todos os valores nos quais takefoi chamado dentro da função, ou seja, todos os caminhos não cíclicos válidos pelo labirinto.

O caminho mais curto é escolhido, cada segunda seta é descartada para explicar o fato de que são necessários dois movimentos idênticos para passar de uma célula para a próxima e as setas restantes são concatenadas para formar a sequência retornada do lambda.


Antes de tudo, um ótimo trabalho em ser o primeiro a completar meu desafio! :) Inteligente como você alterou os dois espaços para um para facilitar o movimento / contagem real. +1 de mim. De qualquer forma, após alguns comentários, dois novos casos de teste foram adicionados. Você também pode verificar estes trabalhos com sua solução? (Além disso, o Perl 6 possui um TIO ou outro compilador online ao qual você pode adicionar um link?)
— Kevin Cruijssen

@KevinCruijssen: Foi ao redor do labirinto nos novos casos de teste. :( Corrigi o código agora. Tio.run suporta Perl 6, mas por algum motivo, isso não funciona lá ... talvez ele tenha uma versão muito antiga do Perl 6?
— SMLS

Ótimo trabalho para corrigir o código. Desculpe por especificar a regra de ter que passar pelo labirinto depois de já ter postado sua resposta, mas um capítulo para corrigi-lo tão rápido. E em relação à versão TIO, não faço ideia. Não é realmente minha experiência ..
— Kevin Cruijssen

Desde que você foi o primeiro a responder ao meu desafio há quatro meses, eu dei a recompensa a você. :) E o Accept é para a resposta Retina um pouco mais curta.
— Kevin Cruijssen

5

Python 2: 302 bytes

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)

Recebe entrada como uma matriz de cadeias, todas com o mesmo comprimento. Imprime 0para a direita, 1para baixo, 2para esquerda e 3para cima.

Explicação

Adotei uma abordagem diferente das outras respostas. Ideia geral: procure recursivamente encontrando o caminho mais curto entre avançar e girar a prancha 90 graus.

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)

Experimente online!


3
Bem-vindo ao PPCG! Esta é uma ótima primeira resposta e estou impressionado que você tenha decidido fazer um desafio bastante difícil como o seu primeiro. Também é inteligente como você colocou paredes ao redor Ipara impedir que o caminho saia do labirinto. Aproveite sua estadia e receba +1 de mim. :)
— Kevin Cruijssen

2

JavaScript (ES6), 356 bytes

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])

Recebe a entrada como uma matriz 2D de caracteres. Cada linha deve ser preenchida à esquerda por um espaço e não deve ter espaço à direita, não importa onde estejam os pontos de partida / chegada.

Usa a ideia de smls de o labirinto para tornar cada célula 1x1 e remover setas repetidas da saída.

Ungolfed e Explained

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
)

Snippet de teste


1

Retina , 416 bytes

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

Experimente online! Se eu tivesse visto essa pergunta quando foi publicada originalmente, esta provavelmente é a resposta que eu daria, então estou postando mesmo assim, mesmo que haja uma resposta muito melhor na Retina. Explicação:

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

Preencha a borda. Isso evita caminhar ao redor do labirinto (por exemplo, no caso de teste 7).

I
#

Coloque um marcador não alfabético na entrada.

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

Preenchimento de inundação da saída para a entrada. Em cada etapa, use uma letra para indicar a melhor direção a seguir (wasd - isso pode ser familiar para os jogadores; eu também havia considerado o hjkl, mas achei muito confuso). Além disso, prefira repetir a mesma direção; isso evita ir para a esquerda / direita entre duas células adjacentes verticalmente.

^
w¶

Suponha que o primeiro passo esteja abaixo.

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

Mas se houver uma letra acima, esquerda ou direita da entrada, mude para a primeira etapa.

{`^(.*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 

Mova o marcador na direção do último movimento, lendo a direção do próximo movimento a partir do quadrado para o qual o marcador está se movendo e adicione-o à lista de direções. Isso se repete até que Useja alcançado.

s`U.*

Exclua tudo após as instruções, pois não é mais necessário.

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

A grade original está em um layout 3 × 2. Ao mover verticalmente, se zig-zag horizontalmente, o preenchimento de inundação otimizará o movimento e moverá apenas 3n-1 caracteres horizontalmente; portanto, ao dividir por três, precisamos arredondar para cima. Verticalmente, apenas dividimos por 2.

Também investiguei uma solução de grade quadrada verdadeira, ou seja, onde a matriz de caracteres é ela própria quadrada, em vez de ser um layout 3 × 2 com uma borda opcional. Embora provavelmente não esteja em conformidade com a pergunta, a capacidade de transpor reduziu a contagem de bytes para 350: Experimente on-line!


Boa resposta, +1! Vejo no seu link do TIO que você adicionou dois em -torno dos caracteres de entrada e saída. Como o desafio é principalmente atravessar o labirinto, acho que está bem, mas estou curioso: quais foram os problemas quando você não colocou aquelas paredes acima / abaixo da Ie U? Além disso, você pode verificar se isso funciona para o caso de teste 7 com o Ie Una parte superior em vez de nos lados? O TIO excede o limite de 60 segundos, por isso não consigo testá-lo. Apesar de ler sua explicação sobre a primeira tentativa de desativação por padrão, presumo que ela funcione bem.
— Kevin Cruijssen 9/08/19

@KevinCruijssen A resposta "secundária" funciona para o caso de teste 7, mas requer caracteres extras: Experimente online! Continua ...
— Neil

@KevinCruijssen A resposta "principal" tinha um erro, pelo qual não conseguia lidar com a saída na linha superior. Ele também possui um bug semelhante à resposta "secundária", na qual prefere andar pelo lado de fora do labirinto, se puder. (Além disso, eu não chegar perto da segunda limite de 60.)
— Neil

Na verdade, eu poderia corrigir as duas respostas preenchendo a borda. Farei isso mais tarde quando tiver tempo.
— Neil
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.