Ефективний рух роботів


24

Відмова: Історія, розказана в цьому питанні, є повністю вигаданою та придумана виключно для того, щоб забезпечити вступ.

Мій бос придбав нового іграшкового робота, і він хоче, щоб я допоміг його програмувати. Він хоче мати можливість ввести прості вказівки зі стрілками, щоб змусити її рухатися. Це вказівки: ^ (для руху вперед) <(для повороту вліво) та> (для повороту праворуч). Однак тепер, коли я запрограмував робота, він хоче додаткової функціональності. Він хоче, щоб я перетворив будь-яку послідовність стрілок, які він вводить, щоб замість того, щоб робот пройшов вказаний шлях, він переміщується до потрібного місця, вказаного місцем, яке б у кінцевому підсумку було б, якби він пройшов введений шлях так само ефективно, як можливо. Я звертаюся до вас, члени PP&CG, щоб допомогти мені у виконанні цього завдання.

Ваше завдання:

Напишіть програму або функцію для перетворення рядка, що складається зі стрілок, у рядок, який максимально швидко дістанеться до місця, вказаного вхідним даним. Поворот займає рівно стільки, скільки рухається назад або вперед.

Вхід:

Рядок зі стрілками, як зазначено вище. За бажанням стрілки можуть бути замінені різними символами, але обов'язково включіть той факт, що ви це зробите у своїй відповіді. У всіх тестових випадках звичайно використовуються стрілки.

Вихід:

Рядок зі стрілками (або вашими еквівалентними символами), які максимально ефективно переносять робота до потрібного пункту призначення.

Випробування:

Зауважте, що пропоновані рішення є лише можливостями, а інші рішення можуть бути дійсними.

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

Оцінка:

Пам'ять робота обмежена, тому у вашій програмі повинен бути найменший кількість можливих байтів.


Оскільки на вході робота закінчується саме там, де він запустився, тому ніяких команд не потрібно переміщувати його туди, наскільки це можливо ефективніше.
Грифон - Відновити Моніку

Ой, неправильно прочитайте рядок. Моє ліжко.
JungHwan Min

Запит на тестовий випадок ^<^^<^^<^^^^-> >^^>^?
JungHwan Min

1
@pizzakingme, вибачте, але мій начальник дуже лінивий і хоче лише вводити один символ на рух.
Грифон - Відновлення Моніки

1
Я програмую конкурентоспроможних роботів, і можу підтвердити, що саме так вони працюють.
Джо

Відповіді:


9

Сітківка , 103 74 71 байт

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

Спробуйте в Інтернеті! Посилання включає тестові випадки. Пояснення:

<
>>>

Поверніть ліворуч на потрійні праві повороти.

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

Зменшити всі витки за модулем 4.

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

Скасуйте рухи в протилежних напрямках.

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

Поверніть потрійний правий поворот назад у лівий поворот. Це також вирішує справу, >>^>^якою потрібно стати <^<^.

<?>*$

Видаліть зайві кінцеві повороти.


Вражає. Я знав, що повинен бути спосіб отримати цей під 100 байт якоюсь мовою, і ваша відповідь раніше була такою близькою. +1
Грифон - Відновіть Моніку

6

Математика, 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на уявну одиницю. Якщо символ є ^, додайте iдо j.

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

Математика 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 дає праворуч).

тому ми сприймаємо свій вхід як складні числа: a 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;}

Спробуйте в Інтернеті!

Приймає рядок як вхідний і виводить найкоротший шлях, який пройшов би вхід.


Ungolfed & коментується

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+і і ()s. (x?"":t)+tможна записати (x?t:t+t)для 1-байтового збереження. Код, що рухається в напрямку, виглядає занадто довго. Також я думаю, що вам, мабуть, варто замінити indexOfі Math.absзі порівняннями.
Ніл

@Neil Дякую! Не могли б ви трохи детальніше замінити indexOfпорівняння?
Birjolaxew

Найкраще, що я міг зробити t-=b=c<'>'||-(c<'^').
Ніл

1

Python 2 , 174 169 165 байт

Відредагуйте 1: -5 байт, дозволяючи напряму знаходитись поза діапазоном 0-3 та видаляючи пробіл.

Відредагуйте 2: -4 байти, змінивши вхід на (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

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

попередження: >^^>^

Робот із реверсом був би корисним.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.