La vita è un labirinto: prendiamo la strada sbagliata prima di imparare a camminare


30

Ingresso:

Un labirinto contenente i personaggi:

  • -- (parete orizzontale);
  • | (parete verticale);
  • + (connessione);
  • (spazio per camminare);
  • I (Ingresso);
  • U (Uscita).

Vale a dire un input potrebbe assomigliare a questo:

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

Produzione:

Il più efficace percorso si deve camminare per arrivare dall'ingresso verso l'uscita del labirinto (attraverso il labirinto), indicato dalle caratteri che indicano sinistra, destra, su e giù (vale a dire >; <; ^; v).

Regole della sfida:

  • Puoi prendere l'input in qualsiasi formato ragionevole. String-array, stringa singola con new-line, char-array 2D, ecc. Sono tutti formati di input possibili.
  • L'output può essere composto da quattro caratteri distinti. Cioè ><^v; →←↑↓; ⇒⇐⇑⇓; RLUD; 0123; ABCD; eccetera.).
  • È possibile aggiungere spazi o trascinare la nuova riga all'output, se si preferisce; questo è facoltativo.
  • I passaggi vengono conteggiati per quadrato (vedere quattro +simboli per i quadrati) e non per carattere.
  • Il labirinto può avere dimensioni da 5x5 a 15x15 e sarà sempre un quadrato (quindi non ci saranno casi di test per labirinti 5x10).
  • Puoi presumere che ogni labirinto abbia uno o più percorsi validi dall'inizio alla fine e produci sempre il più breve (vedi i casi di test 4 e 5).
  • Se sono presenti più percorsi con la stessa lunghezza, è possibile scegliere quale output (vedere il caso di test 6).
  • Non puoi "camminare" fuori dai confini del labirinto (vedi i casi di test 7 e 8).

Regole generali:

  • Questo è , quindi vince la risposta più breve in byte.
    Non lasciare che le lingue di code-golf ti scoraggino dal pubblicare risposte con lingue non codegolfing. Prova a trovare una risposta il più breve possibile per "qualsiasi" linguaggio di programmazione.
  • Per la tua risposta valgono regole standard , quindi puoi usare STDIN / STDOUT, funzioni / metodo con i parametri corretti, programmi completi. La tua chiamata.
  • Sono vietate le scappatoie predefinite .
  • Se possibile, aggiungi un link con un test per il tuo codice.
  • Inoltre, si prega di aggiungere una spiegazione, se necessario.

Casi test:

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<

Labirinti generati usando questo strumento (e in alcuni casi leggermente modificati).


10
Ho trovato una soluzione più breve per il terzo caso di test! v<<<<<<^^^^^(pensa sempre fuori dagli schemi)
Leo

2
Se si può dimostrare che il loro codice produrrà la soluzione più breve, con tempo e memoria sufficienti, è in concorrenza? Anche nel caso di un tempo di esecuzione davvero lungo (fine della moda dell'universo)?
Yytsi,

1
@JackBates È uno scherzo. Cammina letteralmente intorno alla scatola fino all'uscita: D
Yytsi

1
Penso che il primo caso di test sia sbagliato, dovrebbe essere >v>>>vv<v>>v>v>>vvv>>>.
smls

1
@KevinCruijssen Ad esempio, una soluzione che verifica ogni combinazione di "v ^ <>" per una lunghezza fino alla quantità di scatole vuote all'interno del labirinto. La soluzione giusta sarà lì, ma richiede tempo astronomico per il calcolo.
Yytsi,

Risposte:


7

Retina , 338 281 275 273 261 byte

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

Provalo online!


Gli appunti

  • A causa di spazi bianchi significativi, tutti gli spazi ( 0x20) vengono sostituiti con interpunct ( ·) sia in questa risposta che nel collegamento TIO. Il programma funziona bene se gli spazi vengono ripristinati.
  • Utilizza rispettivamente AvKrsu, giù, sinistra e destra. Questi possono essere sostituiti con qualsiasi lettera tranne I.
  • Richiede circa 40 secondi su TIO per il caso di test 15 × 15. Essere pazientare. Rielaborata la parte per trovare il percorso più breve una volta che il percorso ha raggiunto l'uscita. Si scopre che stava impiegando molto tempo.
  • Potrebbe rompersi completamente su labirinti larghi 66 o più celle ma in grado di gestire labirinti di altezza arbitraria. Una correzione per larghezza arbitraria richiede +1 byte.

Spiegazione

Il programma prevede 3 fasi:

  • Una fase di costruzione per convertire il labirinto in un formato compatto che è più facile da lavorare (dettagliato di seguito).
  • Una fase di riempimento per risolvere effettivamente il labirinto utilizzando un algoritmo di riempimento di piena.
  • Una fase di ritorno di ritorno per restituire il percorso più breve all'uscita.

Formato

Poiché il formato originale del labirinto è piuttosto ingombrante, la prima parte del programma lo converte in un formato diverso.

cellule

Nel formato originale, ogni cella è rappresentata come una regione 2 × 3:

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

Poiché la colonna di destra non contiene informazioni, il programma identifica le celle come qualsiasi regione 2 × 2 con a + in alto a sinistra.

Questo ci lascia con 3 tipi di cellule:

  • I Cells : cellule che sono correttamente all'interno del labirinto.
  • Cellule R : cellule che si trovano a destra del labirinto. Questi sono creati dall'imbottitura utilizzata per ospitare l'ingresso o l'uscita. Ad esempio, l'uscitaU nel caso di test 1 si trova in una cella R.
  • Cellule B : cellule che si trovano sotto il labirinto. Come le celle R, queste sono create dall'imbottitura.

Nel nuovo formato, le celle sono rappresentate come una stringa di lunghezza variabile:

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

La parete sinistra e superiore vengono copiate dal formato originale. Il numero di colonna si basa sulla posizione orizzontale della cella e viene utilizzato per l'allineamento (identificando le celle direttamente una sopra / l'altra). Path è una stringa alfabetica utilizzata durante la fase di riempimento per salvare il percorso più breve per raggiungere quella cella. Il marker di percorso e di uscita verrà ulteriormente spiegato.

Semicelle

Sebbene la maggior parte del labirinto siano cellule, ci sono regioni del labirinto che non sono cellule:

  • R Semicelle : se non è presente un'imbottitura corretta, il+ s lungo la parete destra non formano celle poiché si trovano sull'ultima colonna.
  • L Semicelle : se è presente un'imbottitura sinistra, le celle non possono formarsi lì poiché non ce ne sono +a sinistra. Ad esempio, l'ingresso Inel caso di test 1 si trova in una semicella a L.

Tecnicamente, ci sono semicelle T sopra il labirinto (quando c'è un'imbottitura superiore) e semicelle B (lungo la parete inferiore quando non c'è imbottitura inferiore) ma non sono rappresentate nel nuovo formato.

La riga superiore di una mezza cella verrebbe rimossa come parte della costruzione di celle complete nella stessa riga, quindi le mezze celle vengono rappresentate nel nuovo formato come

<wall/exit marker>? <path>

Una mezza cellula R è giusta |. Una semicella L ha solo Iil percorso, solo l'indicatore di uscita e un percorso vuoto, o solo un muro vuoto.

Ingressi ed uscite

Se l'ingresso è a sinistra, a destra o in fondo al labirinto, il marker di ingresso Iverrebbe naturalmente incluso nella (mezza) cella come percorso, che può essere rimosso quando si restituisce il percorso finale.

Se l'ingresso è sopra il labirinto, il primo passo (verso il basso) viene fatto durante la fase di costruzione poiché le semicelle T vengono rimosse durante la costruzione. Ciò mantiene un percorso praticabile in una cella completa. La parete superiore viene chiusa in seguito.

Se l'uscita è a sinistra, a destra o in fondo al labirinto, Uverrebbe naturalmente inclusa nella (mezza) cella. Per evitare di essere confuso con un percorso, al &posto di viene utilizzato il marker di uscita non alfanico U. Il marker di uscita è incorporato in una cella o mezza cella (come specificato sopra).

Se l'uscita è sopra il labirinto, allora sarebbe l'unico buco che può andare sopra la fila superiore di celle (poiché quella per l'ingresso, se presente, sarebbe già chiusa). Qualsiasi percorso che raggiunga quel buco può uscire dal labirinto facendo un passo verso l'alto.

Infine, qualsiasi cella B contenente l'ingresso o l'uscita deve chiudere la parete sinistra per impedire di "risolvere" il labirinto camminando lungo le celle B. Le entrate e le uscite nelle celle R o nelle semicelle L non necessitano di ulteriori elaborazioni poiché l'algoritmo di riempimento dell'inondazione non consente movimenti verticali da / verso loro.

Esempio

Ad esempio, il primo caso di test

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

nel nuovo formato. Puoi convertire altri labirinti qui .


Fase di costruzione

La fase di costruzione costituisce le prime 13 righe del programma.

¶U
¶&

Converte l'uscita in L Mezza cella in Exit Marker

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

Aggiunge i muri a sinistra dell'ingresso e esce nelle celle B.

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

Fa il primo passo se l'ingresso è sopra il labirinto

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

Esegue la conversione effettiva

·v
-v

Chiude il foro di entrata superiore

G`1

Mantiene solo le righe con a 1. Poiché i labirinti sono larghi almeno 5 celle e i numeri di colonna si verificano con incrementi di 3, una riga con celle di nuovo formato deve avere un numero di colonna compreso tra 10 e 19.

·U
&

Converte exit in R Cell o B Cell in exit marker


Fase di riempimento

La fase di riempimento costituisce le successive 8 righe del programma. Utilizza un algoritmo di riempimento per riempire tutte le celle con il percorso più breve per raggiungervi dall'ingresso.

{`

Mette l'intera fase di riempimento su un ciclo per riempire l'intero labirinto.

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

Ogni cella in grado di spostarsi a sinistra lo fa. Una cella è in grado di spostarsi a sinistra se

  1. ha un percorso non vuoto
  2. ha una parete sinistra vuota; e
  3. la cella o L semicella alla sua sinistra ha un percorso vuoto
(\w+)·\d+.\B
$&$1r

Quindi, ogni cella in grado di spostarsi a destra lo fa. Una cella è in grado di muoversi correttamente se

  1. ha un percorso non vuoto
  2. la cella alla sua destra ha una parete sinistra vuota; e
  3. la cella alla sua destra ha un percorso vuoto
(?<=\D\2.(\w+).+?¶.*\D(\d+)[·&])\B
$1v

Quindi, ogni cella in grado di spostarsi verso il basso lo fa. Una cella è in grado di spostarsi verso il basso se

  1. ha un percorso non vuoto
  2. ha almeno una cellula o mezza cellula alla sua destra (cioè non è una cellula R)
  3. la cella sotto di essa (ovvero la cella sulla riga successiva con lo stesso numero di colonna) ha una parete superiore vuota o ha il marker di uscita; e
  4. la cella sottostante ha un percorso vuoto

Nota che le semicelle L non possono spostarsi verso il basso poiché non hanno numeri di colonna.

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

Quindi, ogni cella in grado di spostarsi verso l'alto lo fa. Una cella è in grado di spostarsi verso l'alto se

  1. ha un percorso non vuoto
  2. ha una parete superiore vuota
  3. la cella sopra di essa ha almeno una cella o mezza cellula alla sua destra; e
  4. la cella sopra di essa ha un percorso vuoto

Fase di ritorno

La fase di ritorno costituisce le ultime 5 righe del programma. Questa fase cerca e restituisce il percorso riempito nella cella di uscita.

Il modello del percorso all'uscita dipende da dove si trova l'uscita:

  1. Se l'uscita è in una mezza cella L, allora quella mezza cella sarebbe & <path>
  2. Se l'uscita è in una cella R o cella B, quella cella sarebbe <left wall> <column number> & <path>
  3. Se l'uscita è in una semicella a T, quindi, come notato sopra, la cella I che conduce all'uscita sarebbe <left wall> <column number> · <path>e nella riga superiore.
^.+\d·(\w+)
&$1A

Trova una cella sulla riga superiore con una parete superiore vuota e un percorso non vuoto. Questo si occupa dell'ultimo caso aggiungendo l'ultimo passaggio e il marker di uscita.

M!`&\w+

Corrisponde e restituisce un percorso non vuoto seguendo un indicatore di uscita.

I|&

Rimuove il marker di uscita e il Iprefisso del percorso.


Perché il AvKr? Hanno un significato / sono abbreviazioni per su, giù, sinistra e destra nella tua lingua madre, o c'è un altro motivo per cui hai scelto quei caratteri specifici?
Kevin Cruijssen,

@KevinCruijssen Semplicemente perché devo usare caratteri alfanumerici e AvKrsono la cosa più vicina alle frecce in alfano.
TwiNight,

12

Perl 6 , 259 295 byte

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

Come funziona

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

Questo stringe il labirinto in modo che l'interno di ogni cella sia 1x1 invece di 2x1 caratteri spaziali:

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

Questa è la funzione ricorsiva di ricerca del percorso. Prende tre parametri: la coordinata corrente c=(y,x), l'elenco delle coordinate già visitate ve il percorso pintrapreso finora (come un elenco di caratteri freccia).

Se il personaggio alla coordinata corrente è uno spazio, ricorre ai suoi quattro vicini.
Se il personaggio alla coordinata corrente è a I, si ricorre ai due vicini che non sono "lungo il bordo", per forzare le soluzioni a passare attraverso il labirinto e non attorno ad esso.
Se il carattere alla coordinata corrente è a U, chiama takela stringa di percorso accumulata.

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

La funzione ricorsiva viene inizialmente chiamata con le coordinate della lettera I, che si trova usando una regex.

La gatherparola chiave raccoglie tutti i valori su cui è takestato chiamato all'interno della funzione, ovvero tutti i percorsi non ciclici validi attraverso il labirinto.

Viene scelto il percorso più breve, ogni seconda freccia viene rilasciata per tenere conto del fatto che sono necessarie due mosse identiche per passare da una cella alla successiva e le restanti frecce vengono concatenate per formare la stringa che viene restituita dalla lambda.


Innanzitutto un ottimo lavoro nell'essere il primo a completare la mia sfida! :) Intelligente come hai cambiato i due spazi in uno per facilitare il movimento / conteggio effettivo. +1 da me. Ad ogni modo, dopo alcuni commenti sono stati aggiunti due nuovi casi di test. Potresti verificare che funzionino anche con la tua soluzione? (Inoltre, Perl 6 ha un TIO o un altro compilatore online a cui è possibile aggiungere un collegamento?)
Kevin Cruijssen,

@KevinCruijssen: ha fatto il giro del labirinto nei nuovi casi di test. :( Ho corretto il codice ora. Tio.run supporta Perl 6, ma per qualche ragione, questo non funziona lì ... forse ha una versione Perl 6 troppo vecchia?
smls

Ottimo lavoro nel fissare il codice. Ci scusiamo per aver specificato la regola di dover passare attraverso il labirinto dopo aver già pubblicato la tua risposta, ma chapeau per averlo risolto così in fretta. E per quanto riguarda la versione TIO non ne ho idea. Non proprio la mia esperienza ..
Kevin Cruijssen,

Dato che sei stata la prima a rispondere alla mia sfida quattro mesi fa, ti ho dato la generosità. :) E Accept è per la risposta Retina leggermente più breve.
Kevin Cruijssen,

5

Python 2: 302 byte

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)

Accetta l'input come una matrice di stringhe tutte della stessa lunghezza. Stampa 0a destra, 1in basso, 2a sinistra e 3in alto.

Spiegazione

Ho adottato un approccio diverso rispetto alle altre risposte. Idea generale: ricerca ricorsiva trovando il percorso più breve tra andare dritto e ruotare la tavola di 90 gradi.

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)

Provalo online!


3
Benvenuti in PPCG! Questa è un'ottima prima risposta e sono impressionato che tu abbia deciso di affrontare una sfida piuttosto dura come prima. Inoltre, è intelligente il modo in cui hai posizionato i muri attorno Iper evitare che il percorso vada fuori dal labirinto. Goditi il ​​tuo soggiorno e +1 da parte mia. :)
Kevin Cruijssen il

2

JavaScript (ES6), 356 byte

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

Accetta input come una matrice 2D di caratteri. Ogni riga deve essere imbottita a sinistra di uno spazio e non deve contenere spazi finali, indipendentemente da dove si trovino i punti iniziale / finale.

Usa l'idea di smls di il labirinto per rendere ogni cella 1x1 e rimuovere le frecce ripetute dall'output.

Ungolfed e spiegato

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
)

Test dello snippet


1

Retina , 416 byte

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

Provalo online! Se avessi visto questa domanda quando era stata originariamente pubblicata, questa è probabilmente la risposta che avrei dato, quindi la sto pubblicando comunque, anche se c'è una risposta molto migliore in Retina. Spiegazione:

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

Compila il bordo. Ciò evita di camminare all'esterno del labirinto (ad esempio per il caso di test 7).

I
#

Posizionare un marcatore non alfabetico all'ingresso.

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

Riempi inondazione dall'uscita all'entrata. Ad ogni passo, usa una lettera per indicare la direzione migliore da seguire (wasd - questo potrebbe essere familiare ai giocatori; avevo anche considerato l'hjkl ma l'ho trovato troppo confuso). Inoltre, preferisci ripetere la stessa direzione; questo evita di andare a sinistra / a destra tra due celle adiacenti verticalmente.

^
w¶

Supponiamo che il primo passo sia verso il basso.

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

Ma se c'è una lettera sopra, a sinistra o a destra dell'ingresso, cambiarla al primo passo.

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

Sposta il marcatore nella direzione dell'ultima mossa, leggendo la direzione della mossa successiva dalla casella in cui si sta spostando il marcatore e aggiungilo all'elenco delle direzioni. Questo si ripete fino a quando non Uviene raggiunto.

s`U.*

Elimina tutto dopo le indicazioni in quanto non è più necessario.

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

La griglia originale ha un layout 3 × 2. Mentre ci muoviamo verticalmente se zigzagiamo orizzontalmente il riempimento dell'inondazione ottimizzerà il movimento e sposta solo 3n-1 caratteri in orizzontale, quindi quando si divide per tre, è necessario arrotondare per eccesso. In verticale dividiamo solo per 2.

Ho anche studiato una vera soluzione a griglia quadrata, cioè dove la matrice di caratteri è essa stessa quadrata anziché essere un layout 3 × 2 con un bordo opzionale. Sebbene probabilmente non conforme alla domanda, la possibilità di trasporre ha ridotto il numero di byte a 350: provalo online!


Bella risposta, +1! Vedo nel tuo link TIO che ne hai aggiunti due -sia nei caratteri di entrata che di uscita. Dato che la sfida riguarda principalmente il passaggio attraverso il labirinto, credo che vada bene, ma sono curioso: quali sono stati i problemi quando non hai posizionato quei muri sopra / sotto il Ie U? Inoltre, potresti verificare che funzioni per il caso di test 7 con Ie Uin alto anziché ai lati? TIO supera il limite di 60 secondi, quindi non sono in grado di testarlo da solo. Anche se leggendo la tua spiegazione del primo tentativo di scendere di default, suppongo che dovrebbe funzionare bene.
Kevin Cruijssen,

@KevinCruijssen La risposta "secondaria" funziona per il test case 7 ma richiede caratteri extra: provalo online! continua ...
Neil,

@KevinCruijssen La risposta "principale" aveva un bug per cui non riusciva affatto a far fronte all'uscita sulla linea superiore. Ha anche un bug simile alla risposta "secondaria" in base alla quale preferisce camminare all'esterno del labirinto, se possibile. (Inoltre, non sono arrivato vicino al limite di 60 secondi.)
Neil,

In realtà, ho potuto correggere entrambe le risposte compilando il bordo. Lo farò più tardi quando avrò tempo.
Neil,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.