高效的机器人运动


24

免责声明:这个问题中讲的故事完全是虚构的,仅出于介绍目的而发明。

我的老板得到了一个新的玩具机器人,他要我帮忙编程。他希望能够输入简单的箭头说明使其移动。这些指令是:^(向前移动)<(向左转)和>(向右转)。但是,既然我已经对机器人进行了编程,他就需要其他功能。他希望我变换他输入的任何箭头序列,以使机器人能够有效地移动到所需位置,而不是让机器人按照指示的路径移动,而移动到所需的位置,该位置由如果走过输入的路径将会到达的位置指示可能。我呼吁您,PP&CG的成员,帮助我完成此任务。

你的任务:

编写程序或函数以将由箭头组成的字符串转换为字符串,该字符串将尽快到达输入所指示的位置。旋转所需的时间恰好是向后或向前移动的时间。

输入:

一串箭头,如上所述。如果您愿意,可以用其他字符代替箭头,但请务必在回答中包括您这样做的事实。所有测试用例均正常使用箭头。

输出:

一串箭头(或您的等效字符),这些箭头可以使机器人尽可能高效地到达所需的目的地。

测试用例:

请注意,提供的解决方案仅是可能性,其他解决方案可能是有效的。

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

得分:

机械手的内存有限,因此您的程序必须具有最低的字节数。


因为在输入中机器人会准确地终止于其开始的位置,所以不需要命令就可以将其尽可能高效地移动到那里。
狮ry-恢复莫妮卡

哦,误读了字符串。我的错。
JungHwan Min

测试用例请求^<^^<^^<^^^^-> >^^>^
JungHwan Min

1
@pizzakingme,对不起,但是我的老板很懒,只想输入一个动作一个字符。
狮ry –恢复莫妮卡的时间

1
我对竞争性机器人进行编程,我可以确认这正是它们的工作方式。

Answers:


9

视网膜103 74 71字节

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

在线尝试!链接包括测试用例。说明:

<
>>>

左转变成三重右转。

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

减少所有模数的匝数4。

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

抵消相反方向的运动。

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

向右转三转,再向左转。这也可以处理>>^>^需要变为的情况<^<^

<?>*$

删除不必要的尾随弯。


令人印象深刻。我知道必须有一种方法可以用某种语言来获得此100字节以下的内容,而您的答案之前是如此接近。+1
狮phon-恢复莫妮卡

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

设置j为0,然后设置i为1。

/@#

对于输入中的每个字符...

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

如果字符是>,则乘以i虚数单位。如果字符是>,则除以i虚数单位。如果字符是^,请添加ij

ReIm[ ... ;j]

采取的实部和虚部j。这给出了机器人的直角坐标。

... &@@

将以下内容应用于此结果:


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

设置a为生成带有(input)0字符^s 的字符串(以较大者为准)的函数。

{ ... }

一个List由...

a@#

a应用于第一个输入(的实部j

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

如果第二个输入(的虚部j)大于0>。否则,<。设置s为结果字符。

a@Abs@#2

a 应用于第二个输入的绝对值。

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,用i表示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):"")}

在线尝试!

高尔夫版,带空格

-14字节 @Neil


取消高尔夫:

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+()(x?"":t)+t可以写入(x?t:t+t)以节省1个字节。方向移动代码看起来太长。另外,我认为您应该替换indexOfMath.abs进行比较。
尼尔

@尼尔谢谢!您能详细说明一下用indexOf比较代替吗?
伯乔拉秀

我能做的最好的就是t-=b=c<'>'||-(c<'^')
尼尔

1

Python 2中174个 169 165字节

通过允许方向超出0-3范围并删除空格来编辑1--5字节。

编辑2:-4字节,因为OP允许输入,所以将输入更改为(1、2、3)而不是(<,^,>),并且更改了坐标系以减少距离计算。

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

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

/</?$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

在线尝试!


0

JavaScript(document.getElementById()类),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('^<^^<^^<^^^^')

警报: >^^>^

具有反向功能的机器人会很有用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.