Tempo esagonale del labirinto!


27

Tempo per un'altra sfida di labirinto, ma non come la conosci.

Le regole per questa sfida sono leggermente diverse rispetto alla maggior parte delle sfide del labirinto. I tipi di piastrelle sono definiti come segue:

  • S: La posizione sul labirinto da cui inizi
  • E: La posizione che stai cercando di raggiungere
  • 0: Muro che non puoi attraversare
  • +: Piano che puoi attraversare

Puoi viaggiare in una delle sei direzioni: su-sinistra, su-destra, sinistra, destra, giù-sinistra o giù-destra.

\ /
-S-
/ \

Il labirinto non si avvolge. L'obiettivo è trovare la stringa del percorso più breve da cui Sraggiungere E.

Ingresso:

L'input è rappresentato da linee separate da spazi come i labirinti mostrati. Nessuno spazio finale seguirà una linea.

Produzione:

Una stringa di R, Le Fdove

  • R ruota a destra (in senso orario) di 60 gradi
  • L ruota di sinistra (in senso antiorario) di 60 gradi
  • F ti sposta di uno spazio nella direzione in cui stai puntando

Inizi a indicare left-up

Il percorso più breve viene conteggiato dalla lunghezza della stringa prodotta, non dal numero di posizioni visitate. Il programma deve stampare il percorso più breve come soluzione.

Se il labirinto è irrisolvibile, è necessario eseguire l'output Invalid maze!.

( >>>è l'output)

     0 0 0 0
    0 + 0 + 0
   0 0 0 + + 0
  0 + 0 + 0 + 0
 0 0 + + 0 0 + 0
0 0 + 0 + 0 0 + 0
 E 0 + 0 0 + + 0 
  + + 0 + 0 + 0
   0 0 0 0 0 +
    + 0 + + +
     0 S 0 0

>>>RFRFFLFLFRFFLFFFLFLFFRFLFLFRFRFRF

  + 0 0 0 0 0 0
 0 0 0 0 0 + + 0
0 0 E 0 + 0 0 + 0
 0 0 0 0 0 0 0 +
  0 + 0 0 + + +
   0 0 + + 0 0
    S + 0 0 0

>>>Invalid maze!

0 E S

>>>LF


 E + 0
0 + + +
 0 0 S
  + +

>>>FFLF

  E
 0 +
0 + +
 0 +
  S

>>>RFFLFF

 0 E + 0 0
0 + 0 0 + +
 + 0 + + + 0
  + 0 + 0 + 0
   + + + 0 S

>>>FFLFLFFRFRFFRFF

 E 0 + + 0
0 + 0 + + 0
 + + + 0 + 0
  + 0 0 0 0 0
   + + + + 0
    + 0 S 0

>>>FLFFRFFRFLF

(Nota che alcuni labirinti hanno altre soluzioni che hanno la stessa lunghezza ma non sono elencate qui)


27
Spero in una soluzione di esagonia ...
bkul,

3
Assegnerò un premio di 500 punti a una soluzione Hexagony.
lirtosiast,

@ lirtosiast2 anni dopo, penso che l'esagonia potrebbe essere un tratto per questo problema;)
J Atkin,

Aspettiamo ancora qualche anno.
user202729

Può esserci una nuova riga finale?
user202729,

Risposte:


17

Python 2, 291 byte

def f(M):
 Y=map(max,M).index("S");X=M[Y].find("S");V={()};Q=[(0,0,0,1,"")]
 while Q:
    try:x,y,u,v,p=s=Q.pop(0);c=(Y>=y<=X-2*x)*ord(M[Y-y][X-2*x-y])
    except:c=0
    if c==69:return p
    if{c%2*s[:4]}-V:V|={s[:4]};Q+=(x+u,y+v,u,v,p+"F"),(x,y,-v,u+v,p+"R"),(x,y,u+v,-u,p+"L")
 return"Invalid maze!"

Una funzione, f prende il labirinto come un elenco di righe e restituisce una soluzione, se presente.

Spiegazione

Esegue una prima ricerca nel grafico delle coppie posizione / direzione per trovare il percorso più breve da SaE .

La cosa interessante è trovare un modo compatto per rappresentare posizioni e direzioni su una griglia esagonale, che ammetta un semplice "passo" (cioè, muoversi in una certa direzione) e la rotazione. È allettante usare numeri complessi qui, per rappresentare le coordinate su una griglia "reale" esagonale, ma questa non è una buona idea per una serie di motivi, il più grave dei quali è il fatto che dobbiamo collegare un √3 da qualche parte per farlo funzionare (sin 60 ° = √3 / 2), che, quando si usano numeri in virgola mobile, è un non andare se abbiamo bisogno di precisione assoluta (ad esempio, per tenere traccia degli stati che abbiamo già visitato;) puoi provare ad avviare la tua console JavaScript e a digitare Math.sqrt(3)*Math.sqrt(3) == 3e vedere di persona.

Ma possiamo usare un piccolo trucco! Invece di usare i numeri complessi, definiamo numero esagonale in modo simile, come una coppia di numeri reali un + bh , dove h svolge un ruolo simile a quello immaginario che quando si tratta di numeri complessi. Proprio come con i numeri complessi, possiamo associare la coppia ( a , b ) a un punto sul piano, dove l'asse reale punta a destra, l'asse immaginario punta a 60 ° in su ed entrambi intersecano l'esagono regolare dell'unità quando il reale e le parti immaginarie equivalgono rispettivamente a 1. Mappare questo sistema di coordinate alle celle del labirinto è banale.

Figura 1

Diversamente da i , la costante h è definita dalla relazione h 2 = h - 1 (la risoluzione per h potrebbe rivelare alcune intuizioni). I numeri esagonali possono essere aggiunti e moltiplicati, usando la relazione sopra, in modo molto simile ai numeri complessi: ( a + bh ) + ( c + dh ) = ( a + c ) + ( b + d ) h ,
e ( a + bh ) · ( c + dh ) = ( ac - bd) + ( +annuncio + bc + bd ) h . Queste operazioni hanno la stessa interpretazione geometrica delle loro controparti complesse: l'aggiunta è l'aggiunta di vettori e la moltiplicazione è il ridimensionamento e la rotazione. In particolare, per ruotare un numero esagonale di 60 ° in senso antiorario, lo moltiplichiamo per h :
( a + bh ) · h = - b + ( a + b ) h , e per ruotare lo stesso numero di 60 ° in senso orario, dividiamo di h :
( a + bh ) / h = ( a bh ) · (1 - h ) = (a + b) - ah . Ad esempio, possiamo prendere il numero esagonale dell'unità che punta a destra, 1 = (1, 0), un cerchio completo, andando in senso antiorario, moltiplicandolo per h sei volte:
(1, 0) · h = (0, 1 ); (0, 1) · h = (-1, 1); (-1, 1) · h = (-1, 0); (-1, 0) · h = (0, -1); (0, -1) · h = (1, -1);
(1, -1) · h = (1, 0).

Il programma utilizza in questo modo numeri esagonali per rappresentare la posizione corrente nel labirinto e la direzione corrente, per avanzare nella direzione specificata e per ruotare la direzione verso sinistra e verso destra.


31

Esagonia , 2437 byte

Il tanto atteso programma è qui:

(.=$>({{{({}}{\>6'%={}{?4=$/./\_><./,{}}{<$<\?{&P'_("'"#<".>........_..\></</(\.|/<>}{0/'$.}_.....><>)<.$)).><$./$\))'"<$_.)><.>%'2{/_.>(/)|_>}{{}./..>#/|}.'/$|\})'%.<>{=\$_.\<$))<>(|\4?<.{.%.|/</{=....$/<>/...'..._.>'"'_/<}....({{>%'))}/.><.$./{}{\>$\|$(<><$?..\\<.}_>=<._..\(/.//..\}\.)))))<...2/|$\){}/{..><>).../_$..$_>{0#{{((((/|#.}><..>.<_.\(//$>))<(/.\.\})'"#4?#\_=_-..=.>(<...(..>(/\")<((.\=}}}\>{}{?<,|{>/...(...>($>{)<.>{=P&/(>//(_.)\}=#=\4#|)__.>"'()'\.'..".(\&P'&</'&\$_></}{)<\<0|\<.}.\"\.(.(.(/(\..{.>}=P/|><.(...(..."/<.{"_{{=..)..>})<|><$}}/\}}&P<\(/._...>\$'/.>}/{}}{)..|/(\'.<(\''"")$/{{}})<..'...}}>3#./\$<}|.}|..$.><${{}/>.}}{{<>(""''/..>){<}\?=}{\._=/$/=_>)\{_\._..>)</{\=._.....>(($>}}<.>5#.\/}>)<>-/(.....{\<>}}{{/)\$>=}}}))<...=...(\?{{{?<\<._...}.><..\}}/..>'P&//(\......(..\})"'/./&P'&P{}}&P'<{}\{{{({{{(.\&P=<.><$"&1}(./'"?&'&"\.|>}{?&"?&'P&/|{/&P''</(\..>P&{/&/}{}&'&},/"&P'&?<.|\}{&?"&P'&P'<._.>"&}\(>))<\=}{}<.{/}&?"&"&/"&"?&}\.|>?&"?&{{}}?&//x'&{((<._\($|(}.\/}{/>=&'P&"&/".{3?<.|\"&P'&P}{}&P'<.>&{}}?&"&'P&\=}}<.}/2?".?''5?"/?1{(}\."..../{},<../&//&"&P'&P'&"&"</{}}{{/>"?1''?.'({/}}{}<..>?&"?&}}$>)|P/<.>"&'P&'P&"&"&{/........._/"\$#1}/._.........|,($<'"}'?/_$P#"$0'${)$})$)|........(>/\.#1?<$<|.....>?&}$>=?&"?&/1$..>I;n;v;a;l;i;d;P0;m;a\|\"(}}({=/..$_...\"&P=},}}&P'<.|><....................;...>1"(}}){=/_....>'P&'P&}}_?&/#.>}?4'%\/<...@;1P;e;z<._><>"))'?=<.$$=..\&P}{&</\"><_'|/'&=}<.>{{.<.........|>(/>3")}}){=/=/_.>}P&"?/"<).}_.>?4{=:<.|_...........\$\2$'>4")}}({/."\{&P'&?/><.?|>P...."/=(>(/./(}{{\..>(<>(<>?5'"((..'/...#,</,}{{\.......;.F>..\(...}....._.._..._..._........__..'$......\.<R..$.>))<$}{{&P'&?}<.\$$.\...................$\.<>L\.\(('_"\>}P&"?&{/__/=(.(<.>_)..<...>....\..._.<.....&?=\}=&?"&<.."'>.\>))<.|>))\.|$.>&"?&{{}=P&}?&=}/{\.>&{{P/{">)<|\{<(|\(_(<>\_\?"&P'&P}{{{&<=_.>\&\?"&?<|'{/(/>{{/_>.{/=/\\.>'P&"?&"?&"?/._(\)\\>?&"/_|.>/.$/|$..\\><..\&?}{{}&P'&<}.._>{<|\{}<._$>-")<.>_)<|{)$|..>}=P&"?&"?/...{"./>'P&/=_\{?(/>(<>\(|)__.\&?}}{}&P<}.$.\&P'&P'&<\})))&=<\)<'.'_,><.>"?&'P&'/.|>?&{{}?&"?/>&"?&"?&}}<.".(\\\&?={&P<{..\"&?"&P'&<.?....|.$'\$/\"/.,.>{}{}=/..>&'P&}{{}P/\{}&P{(&?"&?"<'.(\&?"&<}..\?"&?"&<.>P&={}}?&}}P&'P&/.'.>&"?/..>P&}}{{P/\}&P'&?={&?<$}=\"."\P'<{..\'&P'&<....>'P&{}P&"?&{{<\\..>&/$.>}{?&"?/|'$&.P&$P\$'&P={(/..\P\\.\{&?"&?\...\?{{}=<$&P'&P<.,./<?\...{}=P\"&<.>=P&""'?&'P&'/$.#1.>{?1#=$\&'P/\}&P'&?={(,}<._?_&\&?{=&{*=}4<.>P&"?&"?&'P&/1_$>}?&}}=?&){?/\{}&P'&?={&?#<$

Provalo online!

Versione "leggibile":

                             ( . = $ > ( { { { ( { } } { \ > 6 ' % = { } { ? 4 = $ / .
                            / \ _ > < . / , { } } { < $ < \ ? { & P ' _ ( " ' " # < " .
                           > . . . . . . . . _ . . \ > < / < / ( \ . | / < > } { 0 / ' $
                          . } _ . . . . . > < > ) < . $ ) ) . > < $ . / $ \ ) ) ' " < $ _
                         . ) > < . > % ' 2 { / _ . > ( / ) | _ > } { { } . / . . > # / | }
                        . ' / $ | \ } ) ' % . < > { = \ $ _ . \ < $ ) ) < > ( | \ 4 ? < . {
                       . % . | / < / { = . . . . $ / < > / . . . ' . . . _ . > ' " ' _ / < }
                      . . . . ( { { > % ' ) ) } / . > < . $ . / { } { \ > $ \ | $ ( < > < $ ?
                     . . \ \ < . } _ > = < . _ . . \ ( / . / / . . \ } \ . ) ) ) ) ) < . . . 2
                    / | $ \ ) { } / { . . > < > ) . . . / _ $ . . $ _ > { 0 # { { ( ( ( ( / | #
                   . } > < . . > . < _ . \ ( / / $ > ) ) < ( / . \ . \ } ) ' " # 4 ? # \ _ = _ -
                  . . = . > ( < . . . ( . . > ( / \ " ) < ( ( . \ = } } } \ > { } { ? < , | { > /
                 . . . ( . . . > ( $ > { ) < . > { = P & / ( > / / ( _ . ) \ } = # = \ 4 # | ) _ _
                . > " ' ( ) ' \ . ' . . " . ( \ & P ' & < / ' & \ $ _ > < / } { ) < \ < 0 | \ < . }
               . \ " \ . ( . ( . ( / ( \ . . { . > } = P / | > < . ( . . . ( . . . " / < . { " _ { {
              = . . ) . . > } ) < | > < $ } } / \ } } & P < \ ( / . _ . . . > \ $ ' / . > } / { } } {
             ) . . | / ( \ ' . < ( \ ' ' " " ) $ / { { } } ) < . . ' . . . } } > 3 # . / \ $ < } | . }
            | . . $ . > < $ { { } / > . } } { { < > ( " " ' ' / . . > ) { < } \ ? = } { \ . _ = / $ / =
           _ > ) \ { _ \ . _ . . > ) < / { \ = . _ . . . . . > ( ( $ > } } < . > 5 # . \ / } > ) < > - /
          ( . . . . . { \ < > } } { { / ) \ $ > = } } } ) ) < . . . = . . . ( \ ? { { { ? < \ < . _ . . .
         } . > < . . \ } } / . . > ' P & / / ( \ . . . . . . ( . . \ } ) " ' / . / & P ' & P { } } & P ' <
        { } \ { { { ( { { { ( . \ & P = < . > < $ " & 1 } ( . / ' " ? & ' & " \ . | > } { ? & " ? & ' P & /
       | { / & P ' ' < / ( \ . . > P & { / & / } { } & ' & } , / " & P ' & ? < . | \ } { & ? " & P ' & P ' <
      . _ . > " & } \ ( > ) ) < \ = } { } < . { / } & ? " & " & / " & " ? & } \ . | > ? & " ? & { { } } ? & /
     / x ' & { ( ( < . _ \ ( $ | ( } . \ / } { / > = & ' P & " & / " . { 3 ? < . | \ " & P ' & P } { } & P ' <
    . > & { } } ? & " & ' P & \ = } } < . } / 2 ? " . ? ' ' 5 ? " / ? 1 { ( } \ . " . . . . / { } , < . . / & /
   / & " & P ' & P ' & " & " < / { } } { { / > " ? 1 ' ' ? . ' ( { / } } { } < . . > ? & " ? & } } $ > ) | P / <
  . > " & ' P & ' P & " & " & { / . . . . . . . . . _ / " \ $ # 1 } / . _ . . . . . . . . . | , ( $ < ' " } ' ? /
 _ $ P # " $ 0 ' $ { ) $ } ) $ ) | . . . . . . . . ( > / \ . # 1 ? < $ < | . . . . . > ? & } $ > = ? & " ? & / 1 $
  . . > I ; n ; v ; a ; l ; i ; d ; P 0 ; m ; a \ | \ " ( } } ( { = / . . $ _ . . . \ " & P = } , } } & P ' < . |
   > < . . . . . . . . . . . . . . . . . . . . ; . . . > 1 " ( } } ) { = / _ . . . . > ' P & ' P & } } _ ? & / #
    . > } ? 4 ' % \ / < . . . @ ; 1 P ; e ; z < . _ > < > " ) ) ' ? = < . $ $ = . . \ & P } { & < / \ " > < _ '
     | / ' & = } < . > { { . < . . . . . . . . . | > ( / > 3 " ) } } ) { = / = / _ . > } P & " ? / " < ) . } _
      . > ? 4 { = : < . | _ . . . . . . . . . . . \ $ \ 2 $ ' > 4 " ) } } ( { / . " \ { & P ' & ? / > < . ? |
       > P . . . . " / = ( > ( / . / ( } { { \ . . > ( < > ( < > ? 5 ' " ( ( . . ' / . . . # , < / , } { { \
        . . . . . . . ; . F > . . \ ( . . . } . . . . . _ . . _ . . . _ . . . _ . . . . . . . . _ _ . . ' $
         . . . . . . \ . < R . . $ . > ) ) < $ } { { & P ' & ? } < . \ $ $ . \ . . . . . . . . . . . . . .
          . . . . . $ \ . < > L \ . \ ( ( ' _ " \ > } P & " ? & { / _ _ / = ( . ( < . > _ ) . . < . . . >
           . . . . \ . . . _ . < . . . . . & ? = \ } = & ? " & < . . " ' > . \ > ) ) < . | > ) ) \ . | $
            . > & " ? & { { } = P & } ? & = } / { \ . > & { { P / { " > ) < | \ { < ( | \ ( _ ( < > \ _
             \ ? " & P ' & P } { { { & < = _ . > \ & \ ? " & ? < | ' { / ( / > { { / _ > . { / = / \ \
              . > ' P & " ? & " ? & " ? / . _ ( \ ) \ \ > ? & " / _ | . > / . $ / | $ . . \ \ > < . .
               \ & ? } { { } & P ' & < } . . _ > { < | \ { } < . _ $ > - " ) < . > _ ) < | { ) $ | .
                . > } = P & " ? & " ? / . . . { " . / > ' P & / = _ \ { ? ( / > ( < > \ ( | ) _ _ .
                 \ & ? } } { } & P < } . $ . \ & P ' & P ' & < \ } ) ) ) & = < \ ) < ' . ' _ , > <
                  . > " ? & ' P & ' / . | > ? & { { } ? & " ? / > & " ? & " ? & } } < . " . ( \ \
                   \ & ? = { & P < { . . \ " & ? " & P ' & < . ? . . . . | . $ ' \ $ / \ " / . ,
                    . > { } { } = / . . > & ' P & } { { } P / \ { } & P { ( & ? " & ? " < ' . (
                     \ & ? " & < } . . \ ? " & ? " & < . > P & = { } } ? & } } P & ' P & / . '
                      . > & " ? / . . > P & } } { { P / \ } & P ' & ? = { & ? < $ } = \ " . "
                       \ P ' < { . . \ ' & P ' & < . . . . > ' P & { } P & " ? & { { < \ \ .
                        . > & / $ . > } { ? & " ? / | ' $ & . P & $ P \ $ ' & P = { ( / . .
                         \ P \ \ . \ { & ? " & ? \ . . . \ ? { { } = < $ & P ' & P < . , .
                          / < ? \ . . . { } = P \ " & < . > = P & " " ' ? & ' P & ' / $ .
                           # 1 . > { ? 1 # = $ \ & ' P / \ } & P ' & ? = { ( , } < . _ ?
                            _ & \ & ? { = & { * = } 4 < . > P & " ? & " ? & ' P & / 1 _
                             $ > } ? & } } = ? & ) { ? / \ { } & P ' & ? = { & ? # < $

Testato su IDE esoterico: TIO potrebbe andare in timeout su alcuni dei casi di test più grandi ma tutti verificati. Mille grazie a Timwi, questo non sarebbe stato possibile senza l'IDE.

C'è un bel po 'di spazio vuoto, quindi potrei essere stato in grado di adattarlo a un esagono di lunghezza laterale 28 (anziché di lunghezza laterale 29), ma sarà un compito enorme, quindi probabilmente non ci proverò.

Spiegazione di base

Fai clic sulle immagini per una versione più grande e dettagliata.

funzioni

funzioni
Nota: le divisioni sono generalmente corrette, ma a volte possono essere un'ipotesi approssimativa.

Questo codice è abbastanza "funzionale", per quanto Hexagony lo consenta. Ci sono otto funzioni principali in questo codice etichettate nel diagramma sopra, nominate dai numeri con cui sono chiamate (quindi i loro numeri di puntatore alle istruzioni sono quel numero mod 6). In (approssimativo) ordine di chiamata, sono (i nomi tra virgolette sono posizioni in memoria che verranno spiegate in seguito):

  • S: La funzione di partenza - legge l'input e imposta la "matrice di riferimento", quindi inizia il "percorso stack" con i tre percorsi F, Re Lpronti per l'elaborazione principale. Il puntatore di istruzione 0 si sposta sulla funzione 0 mentre l'esecuzione si sposta sulla funzione 1.
  • 1 (-11): La funzione principale: utilizza 2 per ottenere un percorso, 3 per verificarne la validità e, se valido, passa alla funzione -110 / -10 due volte e quindi 4 tre volte per copiare i nuovi percorsi nel "percorso stack ", terminando ritornando a se stesso. Può chiamare la funzione 5 se il percorso si trova nella posizione finale.
  • 2: Ottiene il percorso successivo dallo "stack stack" pronto per l'elaborazione, chiama la funzione -1 se non sono rimasti percorsi nello stack. Ritorna alla funzione 1.
  • 3: accetta una coppia di valori e il numero di spostamento e controlla la "matrice di riferimento" per vedere se il percorso corrente è terminato in una posizione valida. Una posizione valida è l'inizio entro le prime 3 mosse o qualsiasi +entro 2 mosse dalla prima volta che viene raggiunta. Ritorna alla funzione 1.
  • -10 / -110: copia il percorso corrente. Ritorna alla funzione 1.
  • 0: aiuta la funzione 1 a gestire la direzione del movimento con F. Ritorna alla funzione 1.
  • 4: prende una copia del percorso di corrente e interconnessi con funzione di 1 cambiamenti in altrettante percorso con entrambi F, Ro Lallegato. Ritorna alla funzione 1.
  • 5: prende il percorso e stampa il percorso corretto (ad es. FFLF), Quindi termina il programma.
  • -1: stampa Invalid maze!e termina.
  • (Doppie frecce): a causa della mancanza di spazio, la funzione 1 / -11 doveva andare nello spazio sopra la funzione -1.

Memoria

Layout di memoria
Nota: grazie ancora all'IDE esoterico per il diagramma

La memoria è composta da tre parti principali:

  • Matrice di riferimento: la griglia viene memorizzata a parte le colonne 2, con un valore ad ogni passaggio:
    • 0 rappresenta sia una , 0o un luogo valida che è stata letta più mosse fa di quanto sarebbe necessario per uscire dal luogo in qualsiasi direzione.
    • 1 rappresenta un +non ancora raggiunto.
    • (numero più alto) rappresenta il numero di mossa in cui ci saranno state abbastanza mosse per uscire dal luogo in qualsiasi direzione.
    • 10 rappresenta anche una nuova riga: non vengono mai raggiunti presupponendo che seguano immediatamente l'ultimo carattere non vuoto.
  • Rail: è costituito da -1s con un singolo -2a sinistra, consente al puntatore di memoria di tornare rapidamente all'area di elaborazione principale.
  • Stack di percorso: memorizza ciascuno dei percorsi non testati in ordine di ID percorso (che è direttamente correlato al numero di spostamento in modo che i percorsi più brevi vengano testati per primi). Il percorso è memorizzato come segue:
    Layout del percorso
    • Rot: la rotazione alla fine del percorso corrente: 0 per su-sinistra e aumento in senso orario a 5
    • Sposta: il numero di mossa corrente (istruzioni - 1)
    • Path: il percorso corrente, memorizzati in quaternario con F, R, Lcome 1, 2, 3rispettivamente
    • x / y: coordinate alla fine del percorso corrente: x + 1 -1s a destra quindi y valori in alto (anche se y = 0 viene elaborato comunque come 1 allo scopo di separare la rotaia dai dati di riferimento)

Altre posizioni di memoria importanti:

  1. La x / y del Eè memorizzata qui.
  2. Questo spazio viene utilizzato per il passaggio di percorsi all'interno e all'esterno della memoria.
  3. Questa posizione è il centro in cui è memorizzato ciascun percorso durante l'elaborazione.

Il passaggio successivo consiste nell'eseguire il programma attraverso il programma per trovare il percorso labirinto più breve.
Veskah,

So che qualcuno lo pubblicherà. Infine ... / Ho anche un piano diverso, che probabilmente dovrebbe richiedere meno codice del tuo. Non ho mai avuto il tempo di implementarlo.
user202729

@ user202729 sarebbe interessante sentirne parlare. Probabilmente questo metodo può essere giocato a golf di almeno 2 taglie, direi, ma c'è sicuramente qualcosa di meglio là fuori.
boboquack,

1
Sto solo aspettando @lirtosiast.
J Atkin,

1
Scuse per il ritardo.
lirtosiast,

6

Python 3, 466 byte

Probabilmente sarebbe finito più piccolo se avessi usato la ricerca approfondita o qualcosa del genere. Questa mostruosità usa Dijkstra ed è abbastanza veloce, ma molto lunga.

Il codice definisce una funzione Sche accetta una stringa multilinea con il labirinto e restituisce il risultato.

def F(M,L,c):y=M[:M.index(c)].count("\n");return L[y].index(c),y
def S(M):
 L=M.split("\n");Q=[("",)+F(M,L,"S")+(0,)];D={};R=range;H=len;U=R(2**30)
 while Q:
  C,*Q=sorted(Q,key=H);w,x,y,d=C
  for e in R(H(L)>y>-1<x<H(L[y])>0<H(D.get(C[1:],U))>H(w)and(L[y][x]in"+SE")*6):D[C[1:]]=w;E=(d+e)%6;Q+=[(w+",R,RR,RRR,LL,L".split(",")[e]+"F",x+[-1,1,2,1,-1,-2][E],y+[-1,-1,0,1,1,0][E],E)]
 J=min([D.get(F(M,L,"E")+(d,),U)for d in R(6)],key=H);return[J,"Invalid maze!"][J==U]

Ecco un test del codice.

Ungolfed

def find_char(maze, lines, char):
    y = maze[:maze.index(char)].count("\n")
    return lines[y].index(char), y
def solve(maze):
    lines = maze.split("\n")
    x, y = find_char(maze, lines, "S")
    queue = [("", x, y, 0)]
    solutions = {}
    very_long = range(2**30)
    x_for_direction = [-1,1,2,1,-1,-2]
    y_for_direction = [-1,-1,0,1,1,0]
    rotations = ["","R","RR","RRR","LL","L"]
    while len(queue) > 0:
        queue = sorted(queue, key=len)
        current, *queue = queue
        route, x, y, direction = current
        if 0 <= y < len(lines) and 0 <= x < len(lines[y]) and lines[y][x] in "+SE" and len(solutions.get(current[1:], very_long)) > len(route):
            solutions[current[1:]] = route
            for change in range(6):
                changed = (direction + change) % 6
                queue += [(route + rotations[change] + "F", x + x_for_direction[changed], y + y_for_direction[changed], changed)]
    end_x, end_y = find_char(maze, lines, "E")
    solution = min([solutions.get((end_x, end_y, direction), very_long) for direction in range(6)], key=len)
    return "Invalid maze!" if solution == very_long else solution

Wow molto bello. Quanto tempo hai impiegato per scrivere?
J Atkin,

1
@JAtkin Bene, il file è stato creato 1,5 ore fa, anche se non sono sicuro di quanto tempo ho effettivamente trascorso lavorando sul codice. Inoltre, sono le 3 del mattino, quindi la mia produttività è ovviamente al massimo.
PurkkaKoodari,

Bene, ho trascorso più di 2 ore e la maggior parte delle mie era già stata scritta per un labirinto standard.
J Atkin,

Hai una versione non golfata?
J Atkin,

1
@JAtkin È necessario, perché potresti doverti voltare all'inizio. Senza la posizione iniziale con cui avrebbe funzionato L,,R.
PurkkaKoodari,

3

Groovy, 624 byte. Prua, testa!

Tempo che fa rotolare la palla con una grande. Prende una stringa multilinea come argQ

Q={a->d=[0]*4
a.eachWithIndex{x,y->f=x.indexOf('S');e=x.indexOf('E');
if(f!=-1){d[0]=f;d[1]=y}
if(e!=-1){d[2]=e;d[3]=y}}
g=[]
s={x,y,h,i,j->if(h.contains([x, y])|y>=a.size()||x>=a[y].size()|x<0|y<0)return;k = a[y][x]
def l=h+[[x, y]]
def m=j
def n=1
if(h){
o=h[-1]
p=[x,y]
q=[p[0]-o[0],p[1]-o[1]]
n=[[-2,0]:0,[-1,-1]:1,[1,-1]:2,[2,0]:3,[1,1]:4,[-1,1]:5][q]
r=n-i
m=j+((r==-5|r==5)?' LR'[(int)r/5]:['','R','RR','LL','L'][r])+'F'}
if(k=='E')g+=m
if(k=='+'|k=='S'){s(x-2,y,l,n,m)
s(x+2,y,l,n,m)
s(x+1,y+1,l,n,m)
s(x+1,y-1,l,n,m)
s(x-1,y+1,l,n,m)
s(x-1,y-1,l,n,m)}}
s(d[0],d[1],[],1,'')
print(g.min{it.size()}?:"Invalid maze!")}

Versione non golfata:

def map =
        """
  + 0 0 0 0 0 0
 0 0 0 0 0 + + 0
0 0 E 0 + 0 0 + 0
 0 0 0 0 0 0 0 +
  0 + 0 0 + + +
   0 0 + + 0 0
    S + 0 0 0""".split('\n').findAll()
//map =
//        """
// 0 + +
//E + 0 S 0
// 0 0 0 +
//  + + +""".split('\n').findAll()

//map = [""]// TODO remove this, this is type checking only
//map.remove(0)
//reader = System.in.newReader()
//line = reader.readLine()
//while (line != '') {
//    map << line
//    line = reader.readLine()
//}

startAndEnd = [0, 0, 0, 0]
map.eachWithIndex { it, idx ->
    s = it.indexOf('S'); e = it.indexOf('E');
    if (s != -1) {
        startAndEnd[0] = s; startAndEnd[1] = idx
    }
    if (e != -1) {
        startAndEnd[2] = e; startAndEnd[3] = idx
    }
}

def validPaths = []
testMove = { x, y, visited ->// visited is an array of x y pairs that we have already visited in this tree
    if (visited.contains([x, y]) || y >= map.size() || x >= map[y].size() || x < 0 || y < 0)
        return;


    def valueAtPos = map[y][x]
    def newPath = visited + [[x, y]]

    if (valueAtPos == 'E') validPaths += [newPath]
    if (valueAtPos == '+' || valueAtPos == 'S') {
        println "$x, $y passed $valueAtPos"
        testMove(x - 2, y, newPath)
        testMove(x + 2, y, newPath)

        testMove(x + 1, y + 1, newPath)
        testMove(x + 1, y - 1, newPath)

        testMove(x - 1, y + 1, newPath)
        testMove(x - 1, y - 1, newPath)
    }
}

//if (!validPath) invalid()
testMove(startAndEnd[0], startAndEnd[1], [])
println validPaths.join('\n')

//println validPath

def smallest = validPaths.collect {
    def path = ''
    def orintation = 1
    it.inject { old, goal ->
        def chr = map[goal[1]][goal[0]]
        def sub = [goal[0] - old[0], goal[1] - old[1]]
        def newOrin = [[-2, 0]: 0, [-1, -1]: 1, [1, -1]: 2, [2, 0]: 3, [1, 1]:4, [-1, 1]:5][sub]
        def diff = newOrin - orintation// 5L -5R
        def addedPath= ((diff==-5||diff==5)?' LR'[(int)diff/5]:['', 'R', 'RR', 'LL', 'L'][diff]) + 'F'//(diff == 0) ? '' : (diff > 0 ? 'R'*diff : 'L'*(-diff)) + 'F'
//        println "old:$old, goal:$goal chr $chr, orintation $orintation, sub:$sub newOrin $newOrin newPath $addedPath diff $diff"
        path += addedPath
        orintation = newOrin
        goal
    }
    path
}.min{it.size()}
//println "paths:\n${smallest.join('\n')}"
if (smallest)
    println "path $smallest"
else
    println "Invalid maze!"

3

C #, 600 574 byte

Programma completo, accetta input da STDIN, output a STDOUT.

Modifica: c'è stato un bug nella gestione dell'involucro (non si è rotto su nessuno dei casi di test indicati) che avrebbe aggiunto 1 byte, quindi ho fatto un po 'più di golf per compensare.

using Q=System.Console;struct P{int p,d;static void Main(){string D="",L;int w=0,W=0,o,n=1;for(;(L=Q.ReadLine())!=null;D+=L)w=(o=(L+="X").Length+1)>w?o:w;for(;W<D.Length;)D=D.Insert(W+1,"".PadLeft(D[W++]>87?w-W%w:0));P[]K=new P[W*6];var T=new string[W*6];P c=K[o=0]=new P{p=D.IndexOf('S')};for(System.Action A=()=>{if(c.p>=0&c.p<W&System.Array.IndexOf(K,c)<0&&D[c.p]%8>0){T[n]=T[o]+L;K[n]=c;n=D[c.p]==69?-n:n+1;}};o<n;o++){c=K[o];L="R";c.d=++c.d%6;A();L="L";c.d=(c.d+4)%6;A();L="F";c=K[o];c.p+=new[]{~w,1-w,2,1+w,w-1,-2}[c.d%6];A();}Q.WriteLine(n>0?"Invalid maze!":T[-n]);}}

Si inizia leggendo sulla mappa, aggiungendo ( a ciascuna riga in modo da sapere dove finisce, e può tornare indietro e aggiungere un carico di spazi per rendere rettangolare la mappa e con una fila di spazi lungo il lato destro (questo salva noi eseguiamo controlli di avvolgimento come verrà spiegato di seguito). Calcola la larghezza del rettangolo in qualche punto in questo, e accerta la lunghezza totale della mappa.

Successivamente, inizializza tutto per una Breadth-First-Search. Vengono creati due array di grandi dimensioni, uno per memorizzare tutti gli stati che dobbiamo esplorare nella nostra ricerca, l'altro per registrare il percorso che abbiamo preso per raggiungere ogni stato. Lo stato iniziale viene aggiunto all'array dovuto, con i puntatori head e tail preimpostati in qualche modo sopra. Tutto è 1-indicizzato.

Quindi iteriamo fino a quando la coda si schianta contro la testa, o almeno sembra essersi schiantata contro la testa. Per ogni stato che abbiamo visitato, tentiamo di aggiungere un nuovo stato nella stessa posizione in cui siamo ruotati a sinistra o a destra, quindi in uno in cui ci siamo spostati in avanti. Le direzioni sono indicizzate, con la direzione iniziale (impostazione predefinita a0 ) corrispondente a "su-sinistra".

Quando proviamo a mettere in coda uno stato, viene associato controllato, ma non a capo, a causa delle colonne di spazi sul lato destro, che viene raccolto dal "ci è permesso di essere qui?" spunta (non ti è permesso essere negli spazi). Se lo stato è in coda, controlliamo se si trova sulla Ecella e, se lo è, impostiamo la testa della coda in modo che sia meno se stessa, il che provoca l'uscita del ciclo principale e dice all'ultima riga del programma di stampare fuori il percorso corrispondente, piuttosto che il messaggio di errore (che mostra se siamo a corto di stati per espanderci (la coda si schianta in testa)).

using Q=System.Console;

// mod 8 table (the block of zeros is what we are after - it's everywhere we /can't/ go)
//   0 (space)
// O 0
// X 0
// S 3
// + 3
// E 5

struct P
{
    int p,d;
    static void Main()
    {
        // it's probably a bad thing that I have my own standards for naming this stupid read sequence by now
        string D="", // map
        L; // line/path char

        int w=0, // width
        W=0, // full length
        o, // next state to expand
        n=1; // next state to fill

        for(;(L=Q.ReadLine())!=null;D+=L) // read in map
            w=(o=(L+="X").Length+1)>w?o:w; // assertain max length (and mark end, and remove any need for wrap checking)

        // now we need to add those trailing spaces...
        for(;W<D.Length;)
            D=D.Insert(W+1,"".PadLeft(D[W++]>87?w-W%w:0)); // inject a load of spaces if we hit an X

        P[]K=new P[W*6]; // create space for due states (can't be more states than 6*number of cells)
        var T=new string[W*6]; // create space for routes (never done it this way before, kind of exciting :D)
        P c=K[o=0]=new P{p=D.IndexOf('S')}; // set first state (assignment to c is just to make the lambda shut up about unassigned variables)

        // run bfs
        for(

            System.Action A=()=> // this adds c to the list of states to be expanded, if a whole load of checks pass
            {
                if(//n>0& // we havn't already finished - we don't need this, because we can't win on the first turn, so can't win unless we go forward, which we check last
                   c.p>=0&c.p<W& // c is within bounds
                   System.Array.IndexOf(K,c)<0&& // we havn't seen c yet (the && is to prevent the following lookup IOBing)
                   D[c.p]%8>0) // and we can move here (see table at top of code)
                {
                    T[n]=T[o]+L; // store route
                    K[n]=c; // store state
                    n=D[c.p]==69?-n:n+1; // check if we are at the end, if so, set n to be negative of itself so we know, and can look up the route (otherwise, increment n)
                }
            }

            ;o<n;o++) // o<n also catches n<0
        {
            c=K[o]; // take current
            L="R"; // say we are going right
            c.d=++c.d%6; // turn right
            A(); // go!

            L="L"; // say we are going left
            c.d=(c.d+4)%6; // turn left
            A(); // go!

            L="F"; // say we - you get the picture
            c=K[o];
            c.p+=new[]{~w,1-w,2,1+w,w-1,-2}[c.d%6]; // look up direction of travel (~w = -w-1)
            A();
        }

        // check if we visited the end
        Q.WriteLine(n>0?"Invalid maze!":T[-n]); // if n<0, then we found the end, so spit out the corresponding route, otherwise, the maze is invlida
    }
}

Come la maggior parte delle mie ricerche di grafici su questo sito, sto facendo buon uso delle strutture C #, che per impostazione predefinita vengono confrontate in base al valore letterale.


2

Python 2, 703 byte

Non buono come le altre due versioni, ma almeno funziona ahah. Imposta Mnel labirinto.

Dal momento che non ho esperienza nella risoluzione di labirinti, passa solo attraverso un approccio di forza bruta, dove troverà tutte le soluzioni che può non comportare il ritorno su se stesso. Calcola i turni dai più corti, quindi sceglie il risultato più corto da quello.

z=zip;d=z((-1,1,-2,2,-1,1),(-1,-1,0,0,1,1));E=enumerate;D={};t=tuple;o=list;b=o.index
for y,i in E(M.split('\n')):
 for x,j in E(o(i)):
  c=(x,y);D[c]=j
  if j=='S':s=c
  if j=='E':e=c
def P(s,e,D,p):
 p=o(p);p.append(s);D=D.copy();D[s]=''
 for i in d:
  c=t(x+y for x,y in z(s,i))
  if c not in p and c in D:
   if D[c]=='E':L.append(p+[c])
   if D[c]=='+':P(c,e,D,p)
def R(p):
 a=[0,1,3,5,4,2];h=d[0];x=p[0];s=''
 for c in p[1:]:
  r=t(x-y for x,y in z(c,x));n=0
  while h!=r:n+=1;h=d[a[(b(a,b(d,h))+1)%6]]
  s+=['L'*(6-n),'R'*n][n<3]+'F';x=t(x+y for x,y in z(x,h))
 return s
L=[];P(s,e,D,[])
try:l=len(min(L))
except ValueError:print"Invalid maze!"
else:print min([R(i)for i in L if len(i)==l],key=len)

Disordinata versione non golfata:

maze = """
     0 0 0 0
    0 + 0 + 0
   0 0 0 + + 0
  0 + 0 + 0 + 0
 0 0 + + 0 0 + 0
0 0 + 0 + 0 0 + 0
 E 0 + 0 0 + + 0 
  + + 0 + 0 + 0
   0 0 0 0 0 +
    + 0 + + +
     0 S 0 0
     """
directions = [(-1, -1), (1, -1),
              (-2, 0), (2, 0),
              (-1, 1), (1, 1)]


maze_dict = {}
maze_lines = maze.split('\n')
for y, row in enumerate(maze_lines):
    if row:
        for x, item in enumerate(list(row)):
            coordinates = (x, y)
            maze_dict[coordinates] = item
            if item == 'S':
                start = coordinates
            elif item == 'E':
                end = coordinates

list_of_paths = []


def find_path(start, end, maze_dict, current_path=None):
    if current_path is None:
        current_path = []
    current_path = list(current_path)
    current_path.append(start)
    current_dict = maze_dict.copy()
    current_dict[start] = '0'

    for direction in directions:
        new_coordinate = (start[0] + direction[0], start[1] + direction[1])

        if new_coordinate in current_path:
            pass

        elif new_coordinate in current_dict:
            if current_dict[new_coordinate] == 'E':
                list_of_paths.append(current_path + [new_coordinate])
                break
            elif current_dict[new_coordinate] == '+':
                find_path(new_coordinate, end, current_dict, current_path)


find_path(start, end, maze_dict)


def find_route(path):

    heading_R = [0, 1, 3, 5, 4, 2]
    heading = (-1, -1)
    current_pos = path[0]
    current_heading = directions.index(heading)
    output_string = []
    for coordinate in path[1:]:
        required_heading = (coordinate[0] - current_pos[0], coordinate[1] - current_pos[1])

        count_R = 0
        while heading != required_heading:
            count_R += 1
            heading_index = directions.index(heading)
            heading_order = (heading_R.index(heading_index) + 1) % len(heading_R)
            heading = directions[heading_R[heading_order]]

        if count_R:
            if count_R > 3:
                output_string += ['L'] * (6 - count_R)
            else:
                output_string += ['R'] * count_R

        output_string.append('F')
        current_pos = (current_pos[0] + heading[0], current_pos[1] + heading[1])
    return ''.join(output_string)


routes = []
try:
    min_len = len(min(list_of_paths))
except ValueError:
    print "Invalid maze!"
else:
    for i in list_of_paths:
        if len(i) == min_len:
            routes.append(find_route(i))

    print 'Shortest route to end: {}'.format(min(routes, key=len))

Puoi sostituirlo if heading != required_heading: while heading != required_heading: con solowhile heading != required_heading:
J Atkin il

Sì, grazie ahah, avevo notato alcune cose tra cui che quando facevo la versione golf, non ho aggiornato il codice originale, lo farò ora poiché sono appena riuscito a radere qualche altro personaggio
Peter

Bello! (riempiendo il 15 min min)
J Atkin il

<Questo è un tag HTML non riconosciuto, quindi SE no likey.>
CalculatorFeline
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.