Löse ein Rückwärtspfeil-Labyrinth

14

Dies ist ein "Pfeil-Labyrinth":

  v      < 
>     v    
      >  ^ 
>         v
^ <       *

Das *markiert die Stelle, an der Sie fertig werden. Ihr Ziel ist es, zu finden, wo das Labyrinth beginnt (daher umgekehrtes Labyrinth). In diesem Fall ist es das erste >in der zweiten Zeile.

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

Beachten Sie, dass alle Pfeile verwendet werden müssen. Beachten Sie auch, dass Sie davon ausgehen können, dass die Zeilen gleich lang mit Leerzeichen aufgefüllt werden.

Ihr Programm muss das Labyrinth in einer angemessenen Weise eingeben (stdin, aus einer Datei, einem Meldungsfeld usw.), das Labyrinth muss jedoch vollständig intakt sein. Beispielsweise können Sie die durch Kommas getrennten Zeilen nicht eingeben. Die Eingabe muss genau das Labyrinth sein.

Sie müssen den Anfang des Labyrinths in einer angemessenen Weise ausgeben. Zum Beispiel könnten Sie

  • Geben Sie die Koordinaten des Starts aus
  • Gib das gesamte Labyrinth aus, wobei der Startpfeil durch einen ersetzt wird S
  • Gib das gesamte Labyrinth mit allen Pfeilen außer dem Startpfeil aus (Leerzeichen intakt!)
  • etc.

Solange Sie anhand Ihrer Ausgabe erkennen können, welcher Pfeil der Startpfeil ist, ist dies in Ordnung. Zum Beispiel eine Ausgabe von

"0"
"2"

ist in Ordnung, unabhängig von den Zeilenumbrüchen und Anführungszeichen, da man noch erkennen kann, wo der Start war.

Das ist , also gewinnt der kürzeste Code in Bytes.

Türknauf
quelle
Ist es vernünftig anzunehmen, dass auf jeden Pfeil nur ein weiterer Pfeil zeigt? Es wird keinen Fall geben, in dem es mehrere Startpunkte geben könnte.
Danny
Ist "Anfang des Labyrinths" ein Pfeil, von dem aus jeder Pfeil einmal besucht wird? Mit anderen Worten, Dannys Frage + Annahme, es gibt keine Schleifen.
Shiona
3
"Sie können die durch Kommas getrennten Zeilen nicht eingeben; die Eingabe muss genau das Labyrinth sein." Dies scheint eine unnötige Einschränkung zu sein, da "genau das Labyrinth" bereits de facto durch Zeilenumbrüche zwischen den Zeilen begrenzt ist. Warum ein Trennzeichen einem anderen vorziehen?
Jonathan Van Matre
1
@Doorknob Das ist sinnvoll, da man theoretisch eine ganze komprimierte Lösung in die "Begrenzer" kodieren könnte. Ich vermute jedoch, dass die Einschränkung eine gewisse sprachliche Tendenz gegenüber bestimmten Sprachen mit sich bringt. Was passiert , wenn die Regel waren „Eingabezeilen von jedem begrenzt werden kann , ein Zeichen Ihrer Wahl. Alle Zeilen , die von der abgegrenzt werden müssen denselben Charakter.“? Ich denke, die obere Grenze ist nützlich, weil sie eine Domäne erstellt, in der Ihr Programm arbeiten muss .
Jonathan Van Matre
1
@Peter Das heißt nur, dass zum Beispiel in >v^der >auf das zeigt v, nicht auf das ^. Ich bearbeite noch mehr Sachen, wenn ich heute wieder zu Hause an einem Computer bin.
Türklinke

Antworten:

4

GolfScript, 55 Bytes

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

Online-Demo

Es wird davon ausgegangen, dass alle Eingabezeilen mit Leerzeichen gleicher Länge und durch Zeilenumbrüche getrennt sind. Gibt den Byte-Versatz des Startpfeils ab dem Beginn der Eingabezeichenfolge aus (z. B. 12für das Beispiel-Labyrinth in der Challenge).

Insbesondere ermittelt dieses Programm die Byte-Offsets aller Pfeile, auf die kein anderer Pfeil verweist (vorausgesetzt, alle Pfeile verweisen auf einen Pfeil oder ein Ziel; wenn dies nicht zutrifft, kann ein merkwürdiges Verhalten auftreten). Wenn es mehrere solcher Pfeile gibt (die laut Spezifikation in einer gültigen Eingabe nicht möglich sein sollten), werden ihre Offsets standardmäßig einfach in der Ausgabe verkettet. Wenn Sie möchten, können Sie sie n*an das Programm anhängen , um sie stattdessen durch Zeilenumbrüche zu trennen.

De-Golf-Version mit Kommentaren:

:&                     # 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
quelle
1
Sie können 3 Zeichen speichern, wenn Sie inline sind w.
Howard
@ Howard: Huh, also kann ich. Vielen Dank! Musste umbenennen z, &um keinen zusätzlichen Platz zu benötigen. OTOH, ?~.~)macht einen hübschen Smiley. :-)
Ilmari Karonen
5

GolfScript ( 101 100 Bytes)

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

Die Ausgabe erfolgt in der Form, [[x y]]in der die Koordinaten beide auf 0 basieren.

Online-Demo

Die Verarbeitung erfolgt in zwei Phasen: In der ersten Phase wird das Labyrinth in eine Reihe von [x y dx dy]Tupeln umgewandelt. Die zweite Phase ordnet jeden Pfeil / Stern dem Pfeil / Stern zu, auf den er zeigt. (Sternchen verweisen auf sich selbst). Nach der Definition des Problems gibt es genau einen Pfeil, der nicht im Ergebnis dieser Karte enthalten ist, und das ist die Lösung.

Peter Taylor
quelle
Ich habe gerade meine Antwort eingefügt, als Sie dies gepostet haben. Wir hatten die gleiche Idee, aber Sie haben es geschafft, erfolgreich Golf zu spielen. Schön!
Vereos
@ PeterTaylor Ich kann nicht sehen, dass es den Punkt durch Fall richtig behandelt, der in den Kommentaren erwähnt wird.
Howard
@Howard, ich habe keine Ahnung, was dieser Fall ist. Bittet um Klarstellung.
Peter Taylor
Würden Sie freundlicherweise ein Beispiel für Ihre Ein- und Ausgabe posten?
DavidC
@ DavidCarraher finden Sie in der Online-Demo. ;'STUFF'simuliert die Versorgung STUFFüber stdin.
Peter Taylor
2

Mathematica 491 323

Ungolfed mit Kommentaren

Die Prozedur beginnt am Ende ("*"), findet den darauf zeigenden Pfeil und so weiter, bis der Start erreicht ist.

Die Funktion f [Labyrinth].

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

Vorläufer [{Abflachen [{überMe [loc, a], unterMe [loc, a], rechts vonMe [loc, a], links vonMe [loc, a]}, 2], a, Voranstellen [Liste, loc]}]]

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

Golf gespielt

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

Beispiel

Das Labyrinth. Jedes geordnete Paar enthält die Zeile und Spalte einer Zelle. Beispielsweise bezeichnet {2, 3} die Zelle in Zeile 2, Spalte 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} -> "<",{_, _} -> " "}]]

Matze


Eingang

f[maze]

Ausgabe : Der Pfad von Anfang bis Ende.

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

DavidC
quelle
Ihr Eingabeformat ist falsch - "Die Eingabe muss genau das Labyrinth sein".
Türklinke
Die Eingabe ist jetzt das Labyrinth selbst.
DavidC
Ich habe den Code nicht befolgt, aber die Art und Weise, wie Sie die Sache "Die Eingabe ist jetzt das Labyrinth" gelöst haben , ist komisch! +1 ... die Anzahl der Anhänger von "STDIN is universal" ist erstaunlich.
Dr. Belisarius
Ich bin froh, dass Sie die Lösung des Eingabeproblems geschätzt haben.
DavidC
1

Ich glaube, ich habe einen guten Weg gefunden, um das zu lösen, aber ich habe zufällig daran gesogen, es zu spielen. Ich denke, das könnte viel kürzer sein, also werde ich meine Idee erklären, damit andere sie verwenden können, wenn sie es gut finden.

Wenn jeder Pfeil verwendet werden muss, werden alle Pfeile von einem anderen Pfeil gezeigt, außer einem, das ist unsere Lösung.

Das bedeutet, dass wir das Labyrinth nicht rückwärts spielen müssen, sondern von links oben ausgehend für jeden einzelnen den nächstgelegenen Zeigepfeil überprüfen müssen. Dies ist ein echtes Problem für größere Labyrinthe (da Sie nicht alle vier Richtungen überprüfen müssen, sondern nur eine).

Hier ist meine Lösung:

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

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;
            }
        }
    }
}
Vereos
quelle
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";

Diese Lösung setzt voraus, dass sich die Karte in einer lokalen Variablen befindet $m. Die kürzeste Methode, die ich zum Übergeben habe, ist über $_GET: $m=$_GET['m'];bei 14 Byte. Eine unbenutzte Version mit variabler Karte wird unten zur besseren Lesbarkeit bereitgestellt.

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

Hier ist eine frühere, ungolfed Version

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

Liefert den Startpunkt wie x ybei 0-basierten Indizes.

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

Die Eingabe erfolgt in einer Datei namens m.txt. Die Ausgabe ist, (x, y)aber wenn Sie die letzte Druckanweisung in ändern print g, wird die Ausgabe eine Liste [(x, y), (x, y), ...]mit allen Schritten sein, die vom Ende bis zum Anfang erforderlich sind.

gcq
quelle