効率的なロボットの動き


24

免責事項:この質問の中で語られた物語は完全に架空のものであり、イントロを提供する目的でのみ発明されました。

私の上司は新しいおもちゃのロボットを手に入れました。彼は、単純な矢印の指示を入力して、移動できるようにしたいと考えています。これらの指示は次のとおりです。^(前方に移動する場合)<(左折する場合)、>(右折する場合)。しかし、ロボットをプログラミングしたので、彼は追加の機能を望んでいます。彼は、入力された矢印のシーケンスを変換して、ロボットが指定されたパスを取るのではなく、入力されたパスを取った場合に最終的に配置される場所によって示される目的の場所に移動するように、可能。PP&CGのメンバーであるあなたに、この仕事を手伝ってくれるようお願いします。

あなたのタスク:

矢印で構成された文字列を、入力で示された場所にできるだけ早く到達する文字列に変換するプログラムまたは関数を作成します。回転には、前後に移動するのとまったく同じ時間がかかります。

入力:

上記の矢印のストリング。必要に応じて、矢印の代わりに別の文字を使用することもできますが、回答にその事実を必ず含めてください。すべてのテストケースは通常矢印を使用します。

出力:

可能な限り効率的にロボットを目的の目的地に導く矢印のストリング(または同等の文字)。

テストケース:

提供されるソリューションは可能性にすぎず、他のソリューションが有効な場合があることに注意してください。

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

得点:

ロボットのメモリは限られているため、プログラムのバイト数は可能な限り少なくする必要があります。


入力では、ロボットは開始した場所に正確に到達するため、ロボットを可能な限り効率的に移動するためのコマンドは必要ありません。
グリフォン-モニカの復活

ああ、文字列を読み間違えた。私の悪い。
ジョンファンミン

テストケースのリクエスト^<^^<^^<^^^^-> >^^>^
ジョンファンミン

1
@pizzakingme、申し訳ありませんが、私の上司はとても怠け者で、動きごとに1文字だけを入力したいと思っています。
グリフォン-復活モニカ

1
競争力のあるロボットをプログラムしますが、これがまさにそれらが機能することを確認できます。
ジョー

回答:


9

網膜103 74 71バイト

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

オンラインでお試しください!リンクにはテストケースが含まれます。説明:

<
>>>

左折から右折3回になります。

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

4を法とするすべてのターンを減らします。

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

反対方向の動きをキャンセルします。

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

トリプルの右折を左折に戻します。これは、に>>^>^なる必要があるケースも処理します<^<^

<?>*$

不要な後続ターンを削除します。


印象的。ある言語でこのサブ100バイトを取得する方法が必要であることがわかっていたので、以前はあなたの答えは非常に近かった。+1
グリフォン-モニカの復活

6

Mathematica、135バイト

{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]&

List入力として文字列を取ります。

説明

j=0;i=1

設定しj0にし、設定iを1に。

/@#

入力の各文字について...

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

文字がの場合、虚数単位>で乗算iします。文字がの場合、虚数単位>で除算iします。文字がの場合、^に追加ijます。

ReIm[ ... ;j]

の実数部と虚数部を取りjます。これにより、ロボットのデカルト座標が得られます。

... &@@

この結果に次を適用します。


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

またはの文字a列のどちらか大きい方を生成する関数に設定します。(input)0^

{ ... }

List成ります...

a@#

a最初の入力(の実数部j)に適用されます

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

もし第二の入力(の虚数部j)よりも大きくなっています0>。それ以外の場合、<s結果の文字に設定します。

a@Abs@#2

a 2番目の入力の絶対値に適用されます。

If[#<0,s,""]

最初の入力が0より小さい場合、s。それ以外の場合、空の文字列。

a@-#

a入力時間に負の値を適用します。

... <>""

文字列を結合します。


2

Mathematica 119バイト

JungHwanのパスコードに対する最終的な位置は、私のものよりも短いため、それを使用します。おそらくもっと短い方法があると思います...

組み込みAnglePath関数を使用して、最終的な位置を決定します。また、「<」、「^」、および「>」の記号L、F、およびRを定義して、いくつかの引用文字を保存します。

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@#&

使用法:

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

出力:

FFLF

2

ルビー、130バイト

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

使い方

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

オンラインでお試しください!


2

J、90バイト

溶液

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

説明

複素数を使用した巧妙なトリックがあります(iを乗算すると左に90度回転し、-iで右に回転します)。

したがって、入力を複素数として取ります。1は「前方に歩く」ことを表し、i / -iは左と右のターンを表します。

最終的な位置は、この表現で簡単に計算されます。これは、上記の最終的な式の最初(右端)の部分です。

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

上記の短い行が問題を解決するものです。他のすべては、答えをどのようにフォーマットするかを考え出しているだけであり、確実に大幅に削減することができます。

上記の短い行を理解するために、*/\(部分積のスキャン)が入力の各インデックスで直面している位置のリストを提供することに注意してください:iは北、1と-1は東と西、-iは南。しかし、北を向いているので、これらすべてにiを掛ける必要があります。これは、Jで表されますj.(しばらくの間、その文をかみます)。

元の入力が1の場合にのみ実際に「移動」するため、元の入力が1である場合は1、それ以外の場合は0であるブール配列を要素ごとに乗算します=&1*その乗算の結果は、「方向性ステップ」の配列です。最終的な位置は、これらのステップの合計です。+/

検査

残念ながら、なんらかの理由でTIOでこれを機能させることはできませんが、以下をJコンソールに貼り付けると、機能することを確認できます。

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バイト

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

オンラインでお試しください!

文字列を入力として受け取り、入力がたどる最短パスを出力します。


未ゴルフ&コメントあり

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バイト

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):"")}

オンラインでお試しください!

空白のあるゴルフバージョン

@Neilによる-14バイト


ゴルフをしていない:

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

t&3代わりに使用します。これはt%4、ネガティブで機能tするため、4+とを削除できるからです()。1バイトの節約のため(x?"":t)+tに書き込むことができます(x?t:t+t)。方向を変えるコードは長すぎます。また、私はあなたがおそらく置き換えるべきだと思うindexOfMath.abs比較して。
ニール

@ニールありがとう!indexOf比較に置き換えて少し詳しく説明していただけますか?
ビルジョラクセ

私ができることは最高でしたt-=b=c<'>'||-(c<'^')
ニール

1

パイソン2174の 169 165バイト

編集1:方向を0〜3の範囲外にし、空白を削除して、-5バイトにします。

編集2:OPで許可されているため、入力を(<、^、>)ではなく(1、2、3)に変更することで-4バイト、距離計算を削減できるように座標系を変更します。

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]

オンラインでお試しください!

実行されているディクショナリの値を介して最終座標を決定し、最終目標への直接パスを出力します。



0

JavaScript(document.getElementById()kind)、343文字

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

展開された:

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)

}

使用法:

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

アラート: >^^>^

リバースを備えたロボットがあれば便利でしょう。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.