Resolver un laberinto de flecha inversa

14

Este es un "laberinto de flechas":

  v      < 
>     v    
      >  ^ 
>         v
^ <       *

El *marca el lugar donde terminarás. Su objetivo es encontrar dónde comienza el laberinto (por lo tanto, laberinto inverso). En este caso, es el primero >en la segunda línea.

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

Tenga en cuenta que se deben usar todas las flechas. También tenga en cuenta que puede suponer que las líneas se rellenarán con espacios de igual longitud.

Su programa debe ingresar el laberinto de cualquier manera razonable (stdin, desde un archivo, cuadro de mensaje, etc.), sin embargo, el laberinto debe estar completamente intacto. Por ejemplo, no puede ingresar las líneas separadas por comas; La entrada debe ser exactamente el laberinto.

Debe generar el inicio del laberinto de cualquier manera razonable. Por ejemplo, podrías

  • dar salida a las coordenadas del inicio
  • muestra todo el laberinto con la flecha de inicio reemplazada por S
  • muestra todo el laberinto con todas las flechas excepto la flecha de inicio eliminada (¡espacios en blanco intactos!)
  • etc.

Siempre que pueda saber por su salida qué flecha es la flecha de inicio, entonces está bien. Por ejemplo, una salida de

"0"
"2"

está bien, independientemente de las nuevas líneas y comillas, porque todavía se puede saber dónde fue el comienzo.

Este es el , por lo que ganará el código más corto en bytes.

Pomo de la puerta
fuente
¿Es razonable suponer que cada flecha solo tiene otra flecha apuntando hacia ella? ¿No habrá una instancia en la que podría haber múltiples puntos de partida?
Danny
¿Es "inicio del laberinto" una flecha desde la cual se visita una flecha a la otra? En otras palabras, la pregunta + suposición de danny no hay bucles.
shiona
3
"no puede ingresar las líneas separadas por comas; la entrada debe ser exactamente el laberinto". Esto parece una restricción innecesaria, ya que "exactamente el laberinto" ya está delimitado de facto por líneas nuevas entre las filas. ¿Por qué priorizar un delimitador sobre otro?
Jonathan Van Matre
1
@Doorknob Eso es razonable, ya que teóricamente uno podría codificar una solución comprimida completa en los "delimitadores". Sin embargo, sospecho que la restricción introduce un cierto sesgo lingüístico contra ciertos idiomas. ¿Qué pasa si la regla eran "las filas de entrada pueden estar delimitados por cualquiera de un personaje de su elección. Todas las filas deben estar delimitados por el mismo carácter."? Creo que el límite superior es útil porque establece un dominio dentro del cual su programa debe funcionar.
Jonathan Van Matre
1
@Peter Eso solo significa que, por ejemplo, en >v^el >está apuntando al v, no al ^. Editaré más cosas cuando regrese a casa con una computadora hoy.
Pomo de la puerta

Respuestas:

4

GolfScript, 55 bytes

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

Demostración en línea

Asume que todas las líneas de entrada están rellenadas con espacios de la misma longitud y separadas por líneas nuevas. Emite el desplazamiento de bytes de la flecha de inicio desde el inicio de la cadena de entrada (por ejemplo, 12para el laberinto de ejemplo en el desafío).

Específicamente, este programa encuentra los desplazamientos de bytes de todas las flechas que no tienen ninguna otra flecha apuntando hacia ellos (suponiendo que todas las flechas apuntan a una flecha o un objetivo; puede ocurrir un comportamiento extraño si esto no es cierto). Por defecto, si hay varias flechas de este tipo (que, por especificación, no deberían ser posibles en una entrada válida), sus desplazamientos simplemente se concatenarán en la salida. Si lo desea, puede agregar n*al programa para separarlos por nuevas líneas.

Versión de golf con comentarios:

:&                     # 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
Ilmari Karonen
fuente
1
Puede guardar 3 caracteres si está en línea w.
Howard
@Howard: Huh, así que puedo. ¡Gracias! Tuve que cambiar el nombre za& embargo, evitar necesitar un espacio adicional. OTOH, ?~.~)hace una bonita carita sonriente. :-)
Ilmari Karonen
5

GolfScript ( 101 100 bytes)

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

La salida tiene la forma [[x y]]en que las coordenadas están basadas en 0.

Demostración en línea

El procesamiento se realiza en dos fases: la primera fase convierte el laberinto en una serie de [x y dx dy]tuplas; la segunda fase asigna cada flecha / asterisco a la flecha / asterisco al que apunta. (Se considera que los asteriscos apuntan a sí mismos). Según la definición del problema, hay exactamente una flecha que no está en el resultado de este mapa, y esa es la solución.

Peter Taylor
fuente
Estaba pegando mi respuesta mientras publicabas esto. Teníamos la misma idea, pero lograste jugar golf con éxito. ¡Buena esa!
Vereos
@PeterTaylor No puedo ver que maneja el punto a través del caso correctamente que se menciona en los comentarios.
Howard
@Howard, no tengo idea de cuál es ese caso. Pedirá aclaraciones.
Peter Taylor
¿Podría publicar un ejemplo de su entrada y salida?
DavidC
@DavidCarraher, vea la demostración en línea. ;'STUFF'simula el suministro a STUFFtravés de stdin.
Peter Taylor
2

Mathematica 491 323

Ungolfed con comentarios

El procedimiento comienza desde el final ("*"), encuentra la flecha que lo señala, y así sucesivamente hasta llegar al inicio.

La función, f [laberinto].

(* 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 *)

precursor [{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}]]

Ejemplo

El laberinto. Cada par ordenado contiene la fila y la columna de una celda. Por ejemplo, {2, 3} denota la celda en la fila 2, columna 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} -> "<",{_, _} -> " "}]]

laberinto


Entrada

f[maze]

Salida : la ruta de principio a fin.

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

DavidC
fuente
Su formato de entrada es incorrecto: "la entrada debe ser exactamente el laberinto".
Pomo de la puerta
La entrada es ahora el laberinto en sí.
DavidC
¡No he seguido el código, pero la forma en que resolvió la cuestión "la entrada es ahora el laberinto" es graciosa! +1 ... el número de creyentes en "STDIN es universal" es asombroso.
Dr. belisario
Me alegra que haya apreciado la solución al problema de entrada.
DavidC
1

Creo que encontré una buena manera de resolver esto, pero resultó ser un asco jugar al golf. Supongo que esto podría ser MUCHO más corto, así que voy a explicar mi idea para que otros puedan usarla si les parece bien.

Si se debe usar cada flecha, todas las flechas serán apuntadas por otra flecha, excepto una, esa es nuestra solución.

Esto significa que en realidad no tenemos que jugar el laberinto hacia atrás, pero, comenzando por el superior izquierdo, solo tenemos que verificar la flecha apuntable más cercana para cada uno. Este es un verdadero protector del dolor para laberintos más grandes (ya que no tiene que verificar las cuatro direcciones, sino solo una).

Aquí está mi solución:

PHP, 622 bytes

$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;}}}}

Sin golf:

$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;
            }
        }
    }
}
Vereos
fuente
1

PHP - 492 bytes

$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";

Esta solución supone que el mapa se puede encontrar en la variable local $m. El método más corto que tengo para pasar es a través de $_GET: $m=$_GET['m'];a 14 bytes. A continuación se proporciona una versión sin golf con mapa en variable para mayor claridad de lectura.

$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";
Yoda
fuente
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]}

Aquí hay una versión anterior, sin golf

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

Devuelve el punto de partida como x ycon índices basados ​​en 0.

k)maze
"  v      < "
">     v    "
"      >  ^ "
">         v"
"^ <       *"
k)solve maze
1 0
tmartin
fuente
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

La entrada está en un archivo llamado m.txt. La salida es(x, y) pero si cambia la última declaración de impresión a print g, la salida será una lista como [(x, y), (x, y), ...]con todos los pasos para llegar desde el final hasta el comienzo.

gcq
fuente