Effiziente Roboterbewegung


24

Haftungsausschluss: Die Geschichte, die in dieser Frage erzählt wird, ist vollständig fiktiv und wurde ausschließlich zum Zweck der Bereitstellung eines Intro erfunden.

Mein Chef hat einen neuen Spielzeugroboter bekommen und möchte, dass ich ihn programmiere. Er möchte in der Lage sein, einfache Pfeilanweisungen einzugeben, um es zum Bewegen zu bringen. Diese Anweisungen lauten: ^ (vorwärts bewegen) <(links abbiegen) und> (rechts abbiegen). Jetzt, da ich den Roboter programmiert habe, möchte er zusätzliche Funktionen. Er möchte, dass ich jede Folge von Pfeilen, die er eingibt, transformiere, damit der Roboter den angezeigten Pfad nicht nimmt, sondern sich an den gewünschten Ort bewegt, der durch den Ort angegeben wird, an dem er enden würde, wenn er den eingegebenen Pfad genommen hätte, so effizient wie möglich. Ich appelliere an Sie, die Mitglieder von PP & CG, mir bei dieser Aufgabe zu helfen.

Deine Aufgabe:

Schreiben Sie ein Programm oder eine Funktion, um eine Zeichenfolge aus Pfeilen in eine Zeichenfolge umzuwandeln, die so schnell wie möglich an die von der Eingabe angegebene Position gelangt. Das Drehen dauert genauso lange wie das Vor- oder Zurückbewegen.

Eingang:

Eine Reihe von Pfeilen, wie oben angegeben. Wenn Sie möchten, können die Pfeile durch andere Zeichen ersetzt werden. Achten Sie jedoch darauf, dass Sie dies in Ihre Antwort einbeziehen. In allen Testfällen werden die Pfeile normalerweise verwendet.

Ausgabe:

Eine Reihe von Pfeilen (oder Ihren entsprechenden Zeichen), die den Roboter so effizient wie möglich zum gewünschten Ziel bringen.

Testfälle:

Beachten Sie, dass die angebotenen Lösungen nur Möglichkeiten sind und dass andere Lösungen möglicherweise gültig sind.

>^<<^^>^^    -> ^^<^
^^^^>^^^^    -> ^^^^>^^^^
>>>^^^^^^    -> <^^^^^^
>^>^>^>^     -> (empty string)
^<^^<^^<^^^^ -> >^^>^

Wertung:

Der Arbeitsspeicher des Roboters ist begrenzt, daher muss Ihr Programm die niedrigstmögliche Bytezahl haben.


Da der Roboter in der Eingabe genau dort landet, wo er gestartet wurde, sind keine Befehle erforderlich, um ihn so effizient wie möglich dorthin zu bewegen.
Gryphon - Wiedereinsetzung von Monica

Oh, die Saite falsch gelesen. Mein Fehler.
JungHwan Min

Testfallanfrage ^<^^<^^<^^^^-> >^^>^?
JungHwan Min

1
@pizzakingme, sorry, aber mein Chef ist sehr faul und möchte nur einen Charakter pro Bewegung eingeben.
Gryphon - Reinstate Monica

1
Ich programmiere Wettbewerbsroboter und kann bestätigen, dass sie genau so funktionieren.
Joe

Antworten:


9

Retina , 103 74 71 Bytes

<
>>>
+`(>(\^*>){3})\^
^$1
+`\^(>\^*>)\^
$1
>>(\^*)>(\^+)
<$2<$1
<?>*$

Probieren Sie es online! Link enthält Testfälle. Erläuterung:

<
>>>

Biegen Sie links in dreifache Rechtskurven ab.

+`(>(\^*>){3})\^
^$1

Reduzieren Sie alle Umdrehungen modulo 4.

+`\^(>\^*>)\^
$1

Bewegungen in entgegengesetzte Richtungen aufheben.

>>(\^*)>(\^+)
<$2<$1

Dreimal rechts in links abbiegen. Dies behandelt auch den Fall, der werden >>^>^muss <^<^.

<?>*$

Löschen Sie unnötige Schleppkurven.


Beeindruckend. Ich wusste, dass es eine Möglichkeit geben musste, diese Sub-100-Bytes in einer Sprache abzurufen, und Ihre Antwort war zuvor so knapp. +1
Gryphon - Wiedereinsetzung von Monica

6

Mathematica, 135 Bytes

{a="^"~Table~Ramp@#&;a@#,s=If[#2>0,">","<"],a@Abs@#2,If[#<0,s,""],a@-#}<>""&@@ReIm[j=0;i=1;Switch[#,">",i*=I,"<",i/=I,"^",j+=i]&/@#;j]&

Nimmt eine Listder Zeichenfolgen als Eingabe.

Erläuterung

j=0;i=1

Auf j0 und iauf 1 setzen.

/@#

Für jedes eingegebene Zeichen ...

Switch[#,">",i*=I,"<",i/=I,"^",j+=i]

Wenn das Zeichen ist >, multiplizieren Sie imit der imaginären Einheit. Wenn das Zeichen ist >, dividieren Sie idurch die imaginäre Einheit. Wenn das Zeichen ^, fügen Sie izu j.

ReIm[ ... ;j]

Nehmen Sie die realen und imaginären Teile von j. Dies gibt die kartesische Koordinate des Roboters an.

... &@@

Wenden Sie auf dieses Ergebnis Folgendes an:


a="^"~Table~Ramp@#&;

Eingestellt aauf eine Funktion , die eine Zeichenfolge mit erzeugt (input)oder 0Zeichen ^s, je nachdem , was größer ist.

{ ... }

Ein Listbestehend aus ...

a@#

aangewendet auf den ersten Eingang (Realteil von j)

s=If[#2>0,">","<"]

Wenn der zweite Eingang (imaginärer Teil j) größer ist als 0, >. Ansonsten <. Auf sdas resultierende Zeichen setzen.

a@Abs@#2

a wird auf den absoluten Wert der zweiten Eingabe angewendet.

If[#<0,s,""]

Wenn der erste Eingang kleiner als 0, s. Ansonsten leere Zeichenfolge.

a@-#

Anwenden aauf die Eingabe mal negativ.

... <>""

Verbinde die Saiten.


2

Mathematica 119 Bytes

JungHwans endgültige Position zum Pfadcode war kürzer als meine. Ich denke, es gibt wahrscheinlich einen noch kürzeren Weg, dies zu tun ...

Ich benutze die eingebaute AnglePathFunktion, um die endgültige Position zu bestimmen. Ich definiere auch die Symbole L, F und R für "<", "^" und ">", um ein paar Anführungszeichen zu speichern.

L={0,Pi/2};R=-L;F={1,0};{a="F"~Table~Ramp@#&;a@#,s=If[#2>0,"L","R"],a@Abs@#2,If[#<0,s,""],a@-#}<>""&@@Last@AnglePath@#&

Verwendung:

%@{R,F,L,L,F,F,R,F,F}

Ausgabe:

FFLF

2

Ruby , 130 Bytes

->s{w,d=0,1;s.bytes{|b|b>93?w+=d:d*=1i*(b<=>61)};r,c=w.rect;[w=(d=">><"[c<=>0])+?^*c.abs,?^*r.abs+w,w+d+?^*r.abs][r<=>0].chomp ?>}

Wie es funktioniert

->s{
    # We start from (0,0i), direction is +1
    w,d=0,1

    s.bytes{|b|
        # If it's ASCII 94, go one step forward,
        # else multiply direction by +i or -i
        b>93?w+=d:d*=1i*(b<=>61)
    }

    # Get the rectangular representation of the result
    r,c=w.rect

    # Now, create 2 strings of "^" (call them x and y) for horizontal and vertical moves
    # And a single ">" or "<" (call it d) for the direction change
    # If x>0, output x+d+y
    # If x==0, output d+y
    # If x>0, output d+y+d+x
    [w=(d=">><"[c<=>0])+?^*c.abs,?^*r.abs+w,w+d+?^*r.abs][r<=>0]

    #If y==0 we get an extra ">" sometimes
    .chomp ?>
}

Probieren Sie es online!


2

J, 90 Bytes

Lösung

t=.{&' ><'@*
g=.'^'#~|
(t,g@{.,t@-@(*/),g@{:`g@{:,t@{.,g@|@{.@.(0<:{:))@+.@(+/)@(=&1*j.**/\)

Erläuterung

Es gibt einen tollen Trick mit komplexen Zahlen (Multiplizieren mit i bedeutet eine Drehung um 90 Grad nach links und -i ergibt eine Drehung nach rechts).

Also nehmen wir unsere Eingabe als komplexe Zahlen: Eine 1 steht für "Schritt vorwärts" und i / -i für Links- und Rechtskurven.

Die endgültige Position wird mit dieser Darstellung mühelos berechnet. Beachten Sie, dass dies der erste (am weitesten rechts stehende) Teil meines obigen endgültigen Ausdrucks ist:

(+/)@(=&1*j.**/\)

Diese kurze Zeile oben löst das Problem. Alles andere überlegt nur, wie die Antwort formatiert werden soll, und könnte mit Sicherheit deutlich besser abschneiden.

Um die kurze Zeile oben zu verstehen, beachten Sie, dass */\(der Scan der Teilprodukte) Ihnen eine Liste der Positionen gibt, denen Sie bei jedem Index in der Eingabe gegenüberstehen: i ist Nord, 1 und -1 sind Ost und West, und -i ist Süd . Aber da wir beginnen, nach Norden zu blicken, müssen wir alle mit i multiplizieren, was in J dargestellt wird durch j.(kauen Sie einen Moment auf diesen Satz).

Wir "bewegen" uns nur, wenn die ursprüngliche Eingabe 1 ist, und multiplizieren das Ergebnis dann elementweise mit dem booleschen Array 1, wobei die ursprüngliche Eingabe 1 und 0 ist =&1*. Das Ergebnis dieser Multiplikation ist eine Anordnung von "Richtungsschritten". Unsere endgültige Position ist einfach die Summe dieser Schritte:+/

testen

Leider funktioniert dies in TIO aus irgendeinem Grund nicht, aber wenn Sie Folgendes in die J-Konsole einfügen, wird überprüft, ob es funktioniert:

t=.{&' ><'@*
g=.'^'#~|
f=.(t,g@{.,t@-@(*/),g@{:`g@{:,t@{.,g@|@{.@.(0<:{:))@+.@(+/)@(=&1*j.**/\)

NB. test cases
NB. format input as complex numbers
convert=. {&0j1 0j_1 1@:('<>^'&i.)

s=. '^<^^<^^<^^^^'  NB. >^^>^
echo f convert s
s=. '>^<<^^>^^'     NB. ^^<^
echo f convert s
s=. '^^^^>^^^^'     NB. ^^^^>^^^^
echo f convert s
s=. '>>>^^^^^^'     NB. <^^^^^^
echo f convert s
s=. '>^>^>^>^'      NB. empty string
echo f convert s

1

C # (.NET Core) , 349 Byte

n=>{int a=0,b=0,x=0,y=1,t=0,j=0,k=0,w,e,r;var p="";foreach(var c in n){if(c==62){t=x;x=y;y=-t;}if(c<61){t=x;x=-y;y=t;}if(c>63){a+=x;b+=y;}}while(a!=j|b!=k){w=0;e=a-j;r=b-k;if(r>=e&r>=-e){w=b-k;k+=w;}else if(r<=e&r<=-e){p+=">>";w=k-b;k-=w;}else if(r>=e&r<=-e){p+="<";w=j-a;j-=w;}else if(r<=e&r>=-e){p+=">";w=a-j;j+=w;}p+=new string('^',w);}return p;}

Probieren Sie es online!

Nimmt einen String als Eingabe und gibt den kürzesten Pfad aus, den die Eingabe nehmen würde.


Ungolfed & Kommentiert

n =>
{
    // First, calculate the route that the robot is going to take, represented by xy
    int a = 0, b = 0; // The current coordinates (a=x, b=y)
    int x = 0, y = 1; // The movement vector
    int t = 0; // A temp variable
    var p = ""; // The path we are going to return
    // Calculate the path the robot is going to take by input
    foreach (var c in n)
    {
        if (c == '>') { t = x; x = y; y = -t; } // Turn movement vector right
        if (c == '<') { t = x; x = -y; y = t; } //                      left
        if (c == '^') { a += x; b += y; }       // Move forward
    }
    int j = 0, k = 0; // The new movement coordinates (j=x,k=y)
    // While the target position is not reached, move the robot
    while (a != j | b != k)
    {
        int w = 0; // The forward variable, counting how many times we have to go forward
        int e = a - j, r = b - k; // The target position minus the current position (e=x,r=y)
        if (r >= e & r >= -e) { w = b - k; k += w; } // Up
        else if (r <= e & r <= -e) { p += ">>"; w = k - b; k -= w; } // Down
        else if (r >= e & r <= -e) { p += "<"; w = j - a; j -= w; } // Left
        else if (r <= e & r >= -e) { p += ">"; w = a - j; j += w; } // Right
        p += new string('^', w);
    }
    // Return the final path
    return p;
}

1

JavaScript (Node.js) , 187 Byte

s=>{x=y=t=0;r=x=>"^".repeat(x<0?-x:x);for(c of s){t-=b=c<">"||-(c<"^");if(!b)[z=>++y,z=>++x,z=>--y,z=>--x][t&3]()}t=x<0?"<":">";return (y>0?r(y):"")+(x?t+r(x):"")+(y<0?(x?t:t+t)+r(y):"")}

Probieren Sie es online!

Golf Version mit Leerzeichen

-14 Bytes von @Neil


Ungolfed:

s=>{
  // convert turns to up/down/left/right movements to final destination
  let directions = [
    z=>++y, // up
    z=>++x, // right
    z=>--y, // down
    z=>--x  // left
  ];
  let x = y = direction = 0;
  for(c of s){
    let relativeDirection = "<^>".indexOf(c)-1; // relative turn offset: -1 = left, 1 = right
    direction += relativeDirection;
    if(direction<0){direction+=4} // make sure direction%4 > 0
    if(c==="^"){directions[direction%4]()} // do the movement if going forwards
  }
  // convert destination back to turns
  // the most efficient output has up before left/right before down
  let absoluteRepeat = num => "^".repeat(Math.abs(num));
  let turn = x<0 ? "<" : ">";
  let outp = "";
  if (y>0) { outp += absoluteRepeat(y) } // handle up before left/right
  if (x) { outp+=turn+absoluteRepeat(x) } // handle left/right
  if (y<0) { outp += (outp?turn:turn+turn)+absoluteRepeat(y)) } // handle down (including w/o left/right)
  return outp;
}

Verwenden Sie t&3anstelle von, t%4weil das mit Negativ funktioniert, tdamit Sie das 4+und das ()s entfernen können . (x?"":t)+tkann (x?t:t+t)für eine 1-Byte-Einsparung geschrieben werden. Der Richtungscode sieht viel zu lang aus. Auch ich denke du solltest wohl indexOfund Math.absdurch Vergleiche ersetzen .
Neil

@ Neil Danke! Könnten Sie etwas näher auf das Ersetzen indexOfdurch einen Vergleich eingehen?
Birjolaxew

Das Beste, was ich tun konnte, war t-=b=c<'>'||-(c<'^').
Neil

1

Python 2 , 174 169 165 Bytes

Bearbeiten Sie 1: -5 Bytes, indem Sie zulassen, dass die Richtung außerhalb des Bereichs 0-3 liegt, und Leerzeichen entfernen.

Bearbeiten Sie 2: -4 Bytes, indem Sie die Eingabe in (1, 2, 3) anstatt in (<, ^,>) ändern, da dies vom OP zugelassen wurde. Ändern Sie auch mein Koordinatensystem, um die Entfernungsberechnung zu reduzieren.

n,d=[0,0],0
for c in input():exec'd-=1 n[d%2]+=(-1)**(d/2%2) d+=1'.split()[ord(c)-49]
print'2'*n[0]+'13'[n[1]>0]*any(n)+'2'*abs(n[1])+'13'[n[1]>0]*(n[0]<0)+'2'*-n[0]

Probieren Sie es online!

Ermittelt die endgültigen Koordinaten anhand der auszuführenden Wörterbuchwerte und gibt dann nur den direkten Pfad zum Endziel aus.


0

Perl 5 , 185 + 1 (-p) = 186 Bytes

/</?$d--:/>/?$d++:/\^/?$m[$d%4]++:0for/./g;$y=$m[0]-$m[2];$x=$m[1]-$m[3];$q='^'x abs$x;$_=A.$q.B.('^'x-$y);$x<0?y/AB/</:$x?y/AB/>/:0;$_=('^'x$y).($x<0?'<':$x>0?'>':'').$q if$y>0;y/AB//d

Probieren Sie es online!


0

JavaScript (document.getElementById () Art), 343 Zeichen

function b(s){s=s.split('');c=[0,0];r=0;p='';w='<';e='>';n='^';for(i in s){r+=s[i]==e?.5:s[i]==w?-.5:0;r=r>1?-.5:r<-.5?1:r;c[1-Math.ceil(Math.abs(r%1))]+=s[i]==n?r>0?1:-1:0;}x=c[0];y=c[1];j=x<0?-x:x;k=y<0?-y:y;f=function(a){p+=a==j?x<0?w:x>0?e:'':j>k?y<0?w:y>0?e:'':y>0?e+e:'';for(i=0;i<a;i++){p+=n}};if(j>k){f(j);f(k)}else{f(k);f(j)}alert(p)}

erweitert:

function b(s){

s = s.split('');
c = [0, 0];
r = 0;
p = '';
w = '<';
e = '>';
n = '^';

for(i in s){

    r += s[i] == e ? .5 : s[i] == w ? -.5 : 0;
    r = r > 1 ? -.5 : r < -.5 ? 1 : r;

    c[1 - Math.ceil( Math.abs( r%1 ) )] += s[i] == n ? r > 0 ? 1 : -1 : 0;

}

x = c[0];
y = c[1];
j = x < 0 ? -x : x;
k = y < 0 ? -y : y;

f = function(a){

    p += a == j ? x < 0 ? w : x > 0 ? e : '' : j > k ? y < 0 ? w : y > 0 ? e : '' : y > 0 ? e+e : '';

    for( i = 0; i < a; i++){
        p += n
    }

};

if( j>k ){

    f(j);
    f(k)

} else {

    f(k);
    f(j)

}

alert(p)

}

Verwendung:

b('^<^^<^^<^^^^')

Warnungen: >^^>^

Ein Roboter mit Rückwärtsgang wäre sinnvoll gewesen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.