Risolvi un labirinto con la freccia inversa


14

Questo è un "labirinto di frecce":

  v      < 
>     v    
      >  ^ 
>         v
^ <       *

I *segna il punto in cui si finirà. Il tuo obiettivo è trovare dove inizia il labirinto (quindi, labirinto inverso). In questo caso, è il primo >sulla seconda riga.

  v------< 
S-+---v  | 
  |   >--^ 
>-+-------v
^ <       *

Si noti che tutte le frecce devono essere utilizzate. Si noti inoltre che si può presumere che le linee saranno riempite con spazi di uguale lunghezza.

Il programma deve inserire il labirinto in modo ragionevole (stdin, da un file, finestra di messaggio, ecc.), Tuttavia il labirinto deve essere completamente intatto. Ad esempio, non è possibile inserire le righe separate da virgole; l'input deve essere esattamente il labirinto.

Devi produrre l'inizio del labirinto in modo ragionevole. Ad esempio, potresti

  • emette le coordinate dell'inizio
  • emette l'intero labirinto con la freccia iniziale sostituita da un S
  • emette l'intero labirinto con tutte le frecce tranne la freccia iniziale rimossa (spazi bianchi intatti!)
  • eccetera.

Finché puoi capire dal tuo output quale freccia è la freccia iniziale, allora va bene. Ad esempio, un output di

"0"
"2"

va bene, indipendentemente dalle nuove righe e virgolette, perché puoi ancora dire dove è stato l'inizio.

Questo è , quindi vincerà il codice più breve in byte.


È ragionevole supporre che ogni freccia abbia solo un'altra freccia che la punta? Non ci sarà un'istanza in cui potrebbero esserci più punti di partenza, vero?
Danny,

"Start of the Maze" è una freccia da cui ogni altra freccia viene visitata una volta? In altre parole, domanda di danny + ipotesi non ci sono anelli.
shiona,

3
"non puoi inserire le linee separate da virgole; l'input deve essere esattamente il labirinto." Questa sembra una restrizione non necessaria, poiché "esattamente il labirinto" è già di fatto delimitato da nuove linee tra le file. Perché dare la priorità a un delimitatore rispetto a un altro?
Jonathan Van Matre,

1
@Doorknob Questo è ragionevole, dal momento che si potrebbe teoricamente codificare un'intera soluzione compressa nei "delimitatori". Tuttavia, sospetto che la restrizione introduca un certo pregiudizio linguistico contro determinate lingue. E se la regola fosse "Le righe di input possono essere delimitate da uno qualsiasi dei caratteri di tua scelta. Tutte le righe devono essere delimitate dallo stesso carattere."? Penso che il limite superiore sia utile perché stabilisce un dominio all'interno del quale il programma deve funzionare.
Jonathan Van Matre,

1
@Peter Questo significa solo che, ad esempio, nel >v^la >punta al v, non il ^. Modificherò altre cose quando torno a casa su un computer oggi.
Maniglia della porta

Risposte:


4

GolfScript, 55 byte

:&,,{&=42>},.{.&="><^v"?[1-1&n?~.~)]=:d;{d+.&=32=}do}%-

Demo online

Presuppone che tutte le linee di input siano riempite con spazi della stessa lunghezza e separate da nuove righe. Emette l'offset di byte della freccia iniziale dall'inizio della stringa di input (ad es. 12Per il labirinto di esempio nella sfida).

In particolare, questo programma trova gli offset di byte di tutte le frecce che non hanno altre frecce che puntano verso di esse (supponendo che tutte le frecce puntino verso una freccia o un obiettivo; potrebbe verificarsi un comportamento strano se ciò non è vero). Per impostazione predefinita, se sono presenti diverse frecce (che, per specifica, non dovrebbero essere possibili in un input valido), i loro offset verranno semplicemente concatenati nell'output. Se vuoi, puoi aggiungeren* al programma per separarli invece da newline.

Versione de-golf con commenti:

:&                     # save a copy of the input string in the variable "&"
,, { &= 42> },         # make a list of the byte offsets of all arrows 
.                      # duplicate the list and apply the following loop to it:
{
  .                    # make a copy of the original offset...
  &=                   # ...and get the corresponding character in the input
  "><^v" ?             # map the arrow character to integers 0 to 3, and...
  [ 1 -1 &n?~ .~) ]=   # ...map these to +1, -1, -len-1 or +len+1, where len is the...
  :d;                  # ...length of the first input line, and save result as "d"
  { d+ . &= 32= } do   # add d to the byte offset until another non-space is found
} %
-                      # subtract the resulting list of target offsets from the
                       # original list of arrow offsets; this should leave exactly
                       # one offset, which is left on the stack for output

1
Puoi salvare 3 caratteri se sei in linea w.
Howard,

@Howard: Huh, così posso. Grazie! Tuttavia, ho dovuto rinominare zper &evitare di aver bisogno di uno spazio aggiuntivo. OTOH, ?~.~)fa una bella faccina. :-)
Ilmari Karonen,

5

GolfScript ( 101 100 byte)

n/:g,,{:&g=:r,,{&1$r='^v<>*'?70429 3base 2/=++}/}%{,4=},.{2<}%:&\{2/~\{[~2$~@+(@@+(\]&1$?)!}do\;}%^`

L'output è nella forma in [[x y]]cui le coordinate sono entrambe basate su 0.

Demo online

L'elaborazione avviene in due fasi: la prima fase trasforma il labirinto in una matrice di [x y dx dy]tuple; la seconda fase mappa ogni freccia / asterisco sulla freccia / asterisco a cui punta. (Si considera che gli asterischi indichino se stessi). Secondo la definizione del problema, esiste esattamente una freccia che non è nel risultato di questa mappa, e questa è la soluzione.


Stavo solo incollando la mia risposta mentre hai pubblicato questo. Abbiamo avuto la stessa idea, ma sei riuscito a giocare a golf con successo. Ben fatto!
Vereos,

@PeterTaylor Non riesco a vedere che gestisce correttamente il punto attraverso il caso, che è menzionato nei commenti.
Howard,

@Howard, non ho idea di cosa sia quel caso. Chiederà chiarimenti.
Peter Taylor,

Pubblicheresti gentilmente un esempio dei tuoi input e output?
DavidC,

@DavidCarraher, guarda la demo online. ;'STUFF'simula la fornitura STUFFtramite stdin.
Peter Taylor,

2

Mathematica 491 323

Ungolfed di commenti

La procedura inizia dalla fine ("*"), trova la freccia che la punta e così via fino a raggiungere l'inizio.

La funzione, f [labirinto].

(* positions of the arrowheads *)
aHeads[a_]:=Position[m,#]&/@{"^","v",">","<"}

(* position of the final labyrinth exit*)
final[a_]:=Position[a,"*"][[1]];


(* find arrowheads that point to the current location at {r,c} *)
aboveMe[{r_,c_},a_]:=Cases[aHeads[a][[2]],{r1_,c}/;r1<r]
belowMe[{r_,c_},a_]:=Cases[aHeads[a][[1]],{r1_,c}/;r1>r]
rightOfMe[{r_,c_},a_]:=Cases[aHeads[a][[4]],{r,c1_}/;c1>c]
leftOfMe[{r_,c_},a_]:=Cases[aHeads[a][[3]],{r,c1_}/;c1<c]

(*find the precursor arrowhead*)
precursor[{loc_,a_,list_:{}}]:=

(* end the search when the precursor has already been traversed or when there is no precursor *)
Which[MemberQ[list,loc],list,
loc=={},list,True,


(* otherwise find the next precursor *)

precursore [{Flatten [{aboveMe [loc, a], belowMe [loc, a], rightOfMe [loc, a], leftOfMe [loc, a]}, 2], a, Prepend [list, loc]}]]

(* return the path through the maze from start to finish *)
f[maze_]:= precursor[{final[maze[[1]]],maze[[1]]}]

golfed

f@z_:=Module[{p,h,m=z[[1]]},h@a_:=Position[a,#]&/@{"^","v",">","<","*"};
  p[{v_,a_,j_:{}}]:=Module[{r,c,x=Cases},{r,c}=v;
  Which[MemberQ[j,v],j,v=={},j,True,
  p[{Flatten[{x[h[a][[2]],{r1_,c}/;r1<r],x[h[a][[1]],{r1_,c}/;r1>r],
  x[h[a][[4]],{r,c1_}/;c1>c],x[h[a][[3]],{r,c1_}/;c1<c]},2],a,Prepend[j,v]}]]];
  p[{Position[m,"*"][[1]],m}]]

Esempio

Il labirinto. Ogni coppia ordinata contiene la riga e la colonna di una cella. Ad esempio {2, 3} indica la cella nella riga 2, colonna 3.

maze=Grid[Normal@ SparseArray[{{5, 5} -> "*",{1, 2} -> "v", {1, 5} -> "<",{2, 1} -> ">",
   {2, 3} -> "v",{3, 3} -> ">", {3, 5} -> "^",{4, 1} -> ">", {4, 5} -> "v",{5, 1} -> "^", 
   {5, 2} -> "<",{_, _} -> " "}]]

labirinto


Ingresso

f[maze]

Output : il percorso dall'inizio alla fine.

{{2, 1}, {2, 3}, {3, 3}, {3, 5}, {1, 5}, {1, 2}, {5, 2}, {5, 1}, { 4, 1}, {4, 5}, {5, 5}}


Il formato di input è errato: "l'input deve essere esattamente il labirinto".
Maniglia della porta

L'ingresso è ora il labirinto stesso.
DavidC,

Non ho seguito il codice, ma il modo in cui hai risolto la cosa "l'ingresso è ora il labirinto" è esilarante! +1 ... il numero di credenti in "STDIN è universale" è sorprendente.
Dr. belisarius,

Sono contento che tu abbia apprezzato la soluzione al problema di input.
DavidC,

1

Penso di aver trovato un buon modo per risolverlo, ma mi è capitato di succhiare il golf. Immagino che questo potrebbe essere MOLTO più breve, quindi spiegherò la mia idea in modo che altri possano usarla se la trovano buona.

Se è necessario utilizzare ogni freccia, tutte le frecce saranno puntate da un'altra freccia, tranne una, questa è la nostra soluzione.

Ciò significa che in realtà non dobbiamo giocare al labirinto all'indietro, ma, partendo da quello in alto a sinistra, dobbiamo solo controllare la freccia stampabile più vicina per ognuno. Questo è un vero antidolorifico per labirinti più grandi (dal momento che non devi controllare tutte e quattro le direzioni, ma solo una).

Ecco la mia soluzione:

PHP, 622 byte

$h=fopen("a.txt","r");$b=0;while(($z=fgets($h))!==false){$l[$b]=str_split($z,1);$b++;}$v=array("^","<","v",">");$s=array();for($i=0;$i<count($l);$i++){for($j=0;$j<count($l[0]);$j++){if(in_array($l[$i][$j],$v)){switch($l[$i][$j]){case"^":$c=$i-1;while($l[$c][$j]==" ")$c--;$s[]=$c.",".$j;break;case"v":$c=$i+1;while($l[$c][$j]==" ")$c++;$s[]=$c.",".$j;break;case"<":$c=$j-1;while($l[$i][$c]==" ")$c--;$s[]=$i.",".$c;break;case">":$c=$j+1;while($l[$i][$c]==" ")$c++;$s[]=$i.",".$c;break;}}}}for($i=0;$i<count($l);$i++){for($j=0;$j<count($l[0]);$j++){if(in_array($l[$i][$j],$v)){if(!in_array($i.",".$j,$s)){echo$i.",".$j;}}}}

Ungolfed:

$h=fopen("a.txt","r");
$b=0;
while(($z=fgets($h))!==false) {
    $l[$b]=str_split($z,1);
    $b++;
}
//Input ends here
$v = array("^","<","v",">");
$s = array();
//Here i check every arrow, and save every pointed one in $s
for($i=0;$i<count($l);$i++){
    for($j=0;$j<count($l[0]);$j++){
        if(in_array($l[$i][$j],$v)){
            switch($l[$i][$j]) {
                case "^":
                    $c=$i-1;
                    while ($l[$c][$j]==" ")
                        $c--;
                    $s[]=$c.",".$j;
                    break;
                case "v":
                    $c=$i+1;
                    while ($l[$c][$j]==" ")
                        $c++;
                    $s[]=$c.",".$j;
                    break;
                case "<":
                    $c=$j-1;
                    while ($l[$i][$c]==" ")
                        $c--;
                    $s[]=$i.",".$c;
                    break;
                case">":
                    $c=$j+1;
                    while ($l[$i][$c]==" ")
                        $c++;
                    $s[]=$i.",".$c;
                    break;
            }
        }
    }
}
//I check if the arrow is in $s. If not, we have a solution.
for($i=0;$i<count($l);$i++){
    for($j=0;$j<count($l[0]);$j++){
        if (in_array($l[$i][$j],$v)){
            if (!in_array($i.",".$j,$s)){
                echo$i.",".$j;
            }
        }
    }
}

1

PHP - 492 byte

$r=split("\n",$m);$h=count($r);foreach($r as &$k)$k=str_split($k);$l=count($r[0]);$e=strpos($m,"*")+1-$h;$a=$x=$e%$l;$b=$y=floor(($e-$x)/$l);do{$c=0;for(;--$a>=0;){if($r[$b][$a]==">"){$x=$a;$c++;}if($r[$b][$a]!=" ")break;}$a=$x;for(;--$b>=0;){if($r[$b][$a]=="v"){$y=$b;$c++;}if($r[$b][$a]!=" ")break;}$b=$y;for(;++$a<$l;){if($r[$b][$a]=="<"){$x=$a;$c++;}if($r[$b][$a]!=" ")break;}$a=$x;for(;++$b<$h;){if($r[$b][$a]=="^"){$y=$b;$c++;}if($r[$b][$a]!=" ")break;}$b=$y;}while($c>0);echo "$x-$y";

Questa soluzione suppone che la mappa possa essere trovata nella variabile locale $m. Il metodo più breve che ho per passare è tramite $_GET: $m=$_GET['m'];a 14 byte. Una versione non golfata con mappa in variabile è fornita di seguito per chiarezza di lettura.

$m=<<<EOT
  v      < 
>     v    
      >  ^ 
>         v
^ <       * 
EOT;

$r=split("\n",$m);
$h=count($r);
foreach($r as &$k)
    $k=str_split($k);
$l=count($r[0]);

$e=strpos($m,"*")+1-$h;

$a=$x=$e%$l;
$b=$y=floor(($e-$x)/$l);
do{
$c=0;
for(;--$a>=0;)
    {
        if($r[$b][$a]==">"){$x=$a;$c++;}
        if($r[$b][$a]!=" ")break;
    }
$a=$x;
for(;--$b>=0;)
    {
        if($r[$b][$a]=="v")
            {
                $y=$b;
                $c++;
            }
        if($r[$b][$a]!=" ")break;

    }
$b=$y;
for(;++$a<$l;)
    {
        if($r[$b][$a]=="<")
            {
                $x=$a;
                $c++;
            }
        if($r[$b][$a]!=" ")break;
    }
$a=$x;
for(;++$b<$h;)
    {
        if($r[$b][$a]=="^")
            {
                $y=$b;
                $c++;
            }
        if($r[$b][$a]!=" ")break;
    }
$b=$y;
}while($c>0);
echo "$x-$y";

1

K, 281 277 258

{{$[&/x in*:'{{~"*"=x 1}{(s;k . s;k;s:*1_w@&(k ./:w:{{x@&x in y}[(*:'{(x[1]@x 0;x 1)}\[x;(z;y)]);i]}[(h!b,b,a,a:#k:x 2)m;(h!(0 1+;0 -1+;1 0+;-1 0+))m:x 1;x 0])in"*",h:"><v^")}\(x;y;z;x)}[*x;y .*x;y];*x;.z.s[1_x]y]}[i@&~(x ./:i::,/(!#x),/:\:!b::#*x)in" *";x]}

Ecco una versione precedente, non giocata

solve:{[x]
    //j - indices of all possible starting points
    //i - every index
    j::i@&~(x ./:i::,/(!a:#x),/:\:!b:#*x) in " *";

    h::">v<^";

    //d - dictionary mapping each directional character to
    //    increment/decerement it needs to apply to the x/y axis
    d::h!((::;1+);(1+;::);(::;-1+);(-1+;::));

    //e - dictionary mapping each directional character to
    //    the maximum number of moves it should make in a 
    //    given direction
    e::h!b,a,b,a;

    //f - function to produce the indices of each point that is 
    //    passed once we move in a certain direction from a 
    //    certain index
    f::{{x@&x in y}[(last'{(x[0];x[0]@'x 1)}\[x;(y;z)]);i]};

    //g - function that, given a starting and a direction,
    //    moves in that direction until hitting another directional
    //    character. It then moves in the new direction etc. until
    //    it reaches the end point -- *
    g::{[x;y;z]
        {[x]
            q:x 0;m:x 1; k:x 2;
            w:f[e m;d m;q];
            s:*1_w@&(k ./:w)in h,"*";
            m:k . s;
            (s;m;k;s)}\[{~"*"=x 1};(x;y;z;x)]};

    // recursive function that starts at the first possible starting point
    // and plots its way to the end. If all other potential starting points
    // have been touched in this path, then this is the correct starting point.
    // else, recursively call the function with the next possible starting point
    :{$[min "b"$j in last'g[*x;y . *x;y];*x;.z.s[1_x;y]]}[j;x]
  }

Restituisce il punto iniziale come x ycon indici basati su 0.

k)maze
"  v      < "
">     v    "
"      >  ^ "
">         v"
"^ <       *"
k)solve maze
1 0

1

Python 422

with open("m.txt","r") as f:m=f.read().split("\n")
p=[(v.find("*"),p) for p,v in enumerate(m) if "*" in v][0]
g=[]
def f(a):
    x,y=b,c=a
    for p,i in enumerate((lambda x:[l[x] for l in m])(x)):
        if i in "^>v<" and((p<y and i=="v")or(p>y and i=="^")):return b,p
    for p,i in enumerate(m[y]):
        if i in "^>v<" and((p<x and i==">")or(p>x and i=="<")):return p,c
while True:
    z=f(p)
    if z in g:break
    else:g.append(z);p=z
print p

L'input è in un file chiamato m.txt. L'output è (x, y)ma se si modifica l'ultima istruzione di stampa in print g, l'output sarà un elenco come [(x, y), (x, y), ...]con tutti i passaggi da ottenere dall'inizio alla fine.

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.