Résoudre un labyrinthe de flèches inversées

14

Ceci est un "labyrinthe de flèches":

  v      < 
>     v    
      >  ^ 
>         v
^ <       *

Le *marque l'endroit où vous finirez. Votre objectif est de trouver où commence le labyrinthe (d'où le labyrinthe inversé). Dans ce cas, c'est le premier >sur la deuxième ligne.

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

Notez que toutes les flèches doivent être utilisées. Notez également que vous pouvez supposer que les lignes seront remplies d'espaces de longueur égale.

Votre programme doit entrer le labyrinthe de toute manière raisonnable (stdin, à partir d'un fichier, d'une boîte de message, etc.), mais le labyrinthe doit être complètement intact. Par exemple, vous ne pouvez pas saisir les lignes séparées par des virgules; l'entrée doit être exactement le labyrinthe.

Vous devez afficher le début du labyrinthe de toute manière raisonnable. Par exemple, vous pourriez

  • sortir les coordonnées du début
  • sortie du labyrinthe entier avec la flèche de début remplacée par un S
  • afficher le labyrinthe entier avec toutes les flèches sauf la flèche de début supprimée (espace intact!)
  • etc.

Tant que vous pouvez dire par votre sortie quelle flèche est la flèche de début, alors ça va. Par exemple, une sortie de

"0"
"2"

est correct, indépendamment des nouvelles lignes et des guillemets, car vous pouvez toujours dire où était le début.

C'est le , donc le code le plus court en octets gagnera.

Poignée de porte
la source
Est-il raisonnable de supposer que chaque flèche n'a qu'une seule autre flèche pointant vers elle? Il n'y aura pas d'instance où il pourrait y avoir plusieurs points de départ, n'est-ce pas?
Danny
"Début du labyrinthe" est-il une flèche à partir de laquelle chaque autre flèche est visitée une fois? En d'autres termes, la question de Danny + l'hypothèse qu'il n'y a pas de boucles.
shiona
3
"vous ne pouvez pas entrer les lignes séparées par des virgules; l'entrée doit être exactement le labyrinthe." Cela semble être une restriction inutile, car "exactement le labyrinthe" est déjà de facto délimité par des retours à la ligne entre les lignes. Pourquoi privilégier un délimiteur sur un autre?
Jonathan Van Matre
1
@ Doorknob C'est raisonnable, car on pourrait théoriquement coder une solution compressée entière dans les "délimiteurs". Cependant, je soupçonne que la restriction introduit un certain biais linguistique contre certaines langues. Que faire si la règle était « les lignes d'entrée peuvent être délimitées par un un caractère de votre choix. Toutes les lignes doivent être délimitées par le même caractère. »? Je pense que la limite supérieure est utile car elle établit un domaine dans lequel votre programme doit fonctionner.
Jonathan Van Matre
1
@Peter Cela signifie simplement que, par exemple, dans >v^le >pointe vers le v, pas vers le ^. J'éditerai plus de choses quand je rentrerai chez moi aujourd'hui sur un ordinateur.
Poignée de porte

Réponses:

4

GolfScript, 55 octets

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

Démo en ligne

Suppose que toutes les lignes d'entrée sont remplies d'espaces de la même longueur et séparées par des retours à la ligne. Sort le décalage d'octet de la flèche de départ depuis le début de la chaîne d'entrée (par exemple 12pour l'exemple de labyrinthe dans le défi).

Plus précisément, ce programme trouve les décalages d'octets de toutes les flèches qui n'ont aucune autre flèche pointant vers elles (en supposant que toutes les flèches pointent vers une flèche ou un objectif; un comportement étrange peut se produire si ce n'est pas vrai). Par défaut, s'il existe plusieurs de ces flèches (qui, par spécification, ne devraient pas être possibles en entrée valide), leurs décalages seront simplement concaténés dans la sortie. Si vous le souhaitez, vous pouvez ajoutern* au programme pour les séparer par des sauts de ligne à la place.

Version dé-golfée avec commentaires:

:&                     # 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
la source
1
Vous pouvez enregistrer 3 caractères si vous êtes en ligne w.
Howard
@Howard: Huh, donc je peux. Merci! J'ai dû renommer zpour &éviter d'avoir besoin d'un espace supplémentaire. OTOH, ?~.~)fait un joli joli smiley. :-)
Ilmari Karonen
5

GolfScript ( 101 100 octets)

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

La sortie est sous la forme [[x y]]où les coordonnées sont toutes deux basées sur 0.

Démo en ligne

Le traitement se déroule en deux phases: la première phase transforme le labyrinthe en un tableau de [x y dx dy]tuples; la deuxième phase associe chaque flèche / astérisque à la flèche / astérisque vers laquelle elle pointe. (Les astérisques sont considérés comme pointant vers eux-mêmes). Selon la définition du problème, il y a exactement une flèche qui n'est pas dans le résultat de cette carte, et c'est la solution.

Peter Taylor
la source
Je viens de coller ma réponse pendant que vous publiez ceci. Nous avons eu la même idée, mais vous avez réussi à jouer au golf avec succès. Joli!
Vereos
@PeterTaylor Je ne vois pas qu'il gère correctement le point à point, ce qui est mentionné dans les commentaires.
Howard
@Howard, je n'ai aucune idée de ce qu'est ce cas. Va demander des éclaircissements.
Peter Taylor
Souhaitez-vous publier un exemple de vos entrées et sorties?
DavidC
@DavidCarraher, voir la démo en ligne. ;'STUFF'simule la fourniture STUFFvia stdin.
Peter Taylor
2

Mathematica 491 323

Non golfé avec des commentaires

La procédure commence à l'arrivée ("*"), trouve la flèche qui pointe vers elle, et ainsi de suite jusqu'au départ.

La fonction, f [labyrinthe].

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

précurseur [{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]]}]

Golfé

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

Exemple

Le labyrinthe. Chaque paire ordonnée contient la ligne et la colonne d'une cellule. Par exemple, {2, 3} désigne la cellule de la ligne 2, colonne 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} -> "<",{_, _} -> " "}]]

Labyrinthe


Contribution

f[maze]

Sortie : le chemin du début à la fin.

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

DavidC
la source
Votre format d'entrée est incorrect - "l'entrée doit être exactement le labyrinthe".
Poignée de porte
L'entrée est maintenant le labyrinthe lui-même.
DavidC
Je n'ai pas suivi le code, mais la façon dont vous avez résolu le problème "l'entrée est maintenant le labyrinthe" est hilarante! +1 ... le nombre de croyants en "STDIN est universel" est étonnant.
Dr belisarius
Je suis heureux que vous ayez apprécié la solution au problème de saisie.
DavidC
1

Je pense que j'ai trouvé un bon moyen de résoudre ce problème, mais il m'est arrivé de craindre de jouer au golf. Je suppose que cela pourrait être BEAUCOUP plus court, donc je vais expliquer mon idée afin que les autres puissent l'utiliser s'ils la trouvent bonne.

Si chaque flèche doit être utilisée, alors toutes les flèches seront pointées par une autre flèche, sauf une, c'est notre solution.

Cela signifie que nous n'avons pas réellement à jouer le labyrinthe à l'envers, mais, en partant du coin supérieur gauche, nous avons juste besoin de vérifier la flèche pointable la plus proche pour chacun. C'est un vrai épargnant pour les grands labyrinthes (puisque vous n'avez pas à vérifier les quatre directions, mais une seule).

Voici ma solution:

PHP, 622 octets

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

Non 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
la source
1

PHP - 492 octets

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

Cette solution suppose que la carte peut être trouvée dans une variable locale $m. La méthode la plus courte que j'ai pour passer c'est via $_GET: $m=$_GET['m'];à 14 octets. Une version non golfée avec carte en variable est fournie ci-dessous pour plus de clarté de lecture.

$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
la source
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]}

Voici une version antérieure, non golfée

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

Renvoie le point de départ comme x ypour les index basés sur 0.

k)maze
"  v      < "
">     v    "
"      >  ^ "
">         v"
"^ <       *"
k)solve maze
1 0
tmartin
la source
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'entrée se trouve dans un fichier appelé m.txt. La sortie est (x, y)mais si vous changez la dernière instruction d'impression en print g, la sortie sera une liste comme [(x, y), (x, y), ...]avec toutes les étapes pour aller de la fin au début.

gcq
la source