효율적인 로봇 운동


24

면책 조항 :이 질문에서 들었던 이야기는 전적으로 허구이며 소개를 제공하기위한 목적으로 만 고안되었습니다.

내 상사는 새로운 장난감 로봇을 얻었고 프로그래밍을 도와 주길 원합니다. 그는 간단한 화살표 명령을 입력하여 이동시킬 수 있기를 원합니다. 이 지시 사항은 다음과 같습니다 : ^ (앞으로 이동) <(왼쪽으로 회전) 및> (오른쪽으로 회전). 그러나 이제 로봇을 프로그래밍 했으므로 추가 기능이 필요합니다. 그는 내가 입력 한 화살표 시퀀스를 변환하기를 원하므로 로봇이 표시된 경로를 가져 가지 않고 원하는 경로로 이동합니다. 가능한. PP & CG 회원 여러분 께이 과제를 도와 주실 것을 부탁드립니다.

당신의 작업 :

화살표로 구성된 문자열을 가능한 빨리 입력으로 표시된 위치에 도달하는 문자열로 변환하는 프로그램 또는 함수를 작성하십시오. 앞뒤로 움직일 때까지 정확히 돌리는 데 시간이 걸립니다.

입력:

위에 표시된 바와 같이 일련의 화살표. 원하는 경우 화살표 대신 다른 문자를 사용할 수 있지만 답에 그 사실을 포함시켜야합니다. 모든 테스트 케이스는 화살표를 정상적으로 사용합니다.

산출:

로봇을 가능한 한 효율적으로 원하는 목적지로 안내하는 일련의 화살표 (또는 동등한 문자).

테스트 사례 :

제공된 솔루션은 가능성 일 뿐이며 다른 솔루션도 유효 할 수 있습니다.

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

채점 :

로봇의 메모리는 제한되어 있으므로 프로그램의 바이트 수가 가장 적어야합니다.


입력에서 로봇은 정확히 시작된 곳에서 끝나므로 가능한 효율적으로 로봇을 이동시키기위한 명령이 필요하지 않습니다.
그리폰 (Gryphon)-복원 상태 Monica

아, 문자열을 잘못 읽습니다. 내 잘못이야.
JungHwan Min

테스트 케이스 요청 ^<^^<^^<^^^^-> >^^>^?
JungHwan Min

1
@pizzakingme, 죄송하지만 내 상사는 매우 게으 르며 한 번에 한 문자 만 입력하고 싶습니다.
그리폰 (Gryphon)-복원 자 Monica Monica

1
경쟁 로봇을 프로그래밍하고 이것이 정확히 어떻게 작동하는지 확인할 수 있습니다.
Joe

답변:


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으로하고, 설정 i1.

/@#

입력 된 각 문자에 대해 ...

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

캐릭터가 >i경우 허수를 곱 하십시오. 문자가 >i경우 허수 단위로 나눕니다 . 문자 인 경우 ^, 추가 ij.

ReIm[ ... ;j]

의 실제 및 가상 부분을 가져 가라 j. 이것은 로봇의 직교 좌표를 제공합니다.

... &@@

이 결과에 다음을 적용하십시오.


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

또는 문자 s a를 사용하여 문자열을 생성하는 함수로 설정하십시오 .(input)0^

{ ... }

List로 구성된 ...

a@#

a첫 번째 입력에 적용됨 (의 실제 부분 j)

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

제 2 입력 (허수 부분이있는 경우 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 는 남쪽입니다 . 그러나 우리가 북쪽을 향하기 시작하면, 우리는 J에 의해 표현되는 i 를 곱해야 합니다.j. (잠깐 그 문장을 씹습니다).

원래 입력이 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 코어) , 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;}

온라인으로 사용해보십시오!

문자열을 입력으로 받아서 입력에 걸리는 최단 경로를 출력합니다.


Ungolfed & Commented

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

자바 스크립트 (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+()s를 제거 할 수 있으므로 대신 사용하십시오 . 1 바이트 절약을 위해 (x?"":t)+t쓸 수 있습니다 (x?t:t+t). 방향 이동 코드가 너무 길어 보입니다. 또한 나는 아마도 당신이 비교 indexOf하고 바꿔야한다고 생각합니다 Math.abs.
Neil

@ 닐 감사합니다! indexOf비교로 대체하는 방법을 좀 더 자세히 설명해 주 시겠습니까?
Birjolaxew

내가 할 수있는 최선은 t-=b=c<'>'||-(c<'^').
Neil

1

파이썬 2 , (174) 169 165 바이트

방향이 0-3 범위를 벗어나도록 허용하고 공백을 제거하여 1 : -5 바이트를 편집하십시오.

OP가 허용 한 이후 입력을 (<, ^,>) 대신 (1, 2, 3)으로 변경하고 거리 계산을 줄일 수 있도록 좌표계를 변경하여 2 : 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

펄 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('^<^^<^^<^^^^')

경고 : >^^>^

리버스 로봇이 유용했을 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.