Эффективное движение роботов


24

Отказ от ответственности: история, рассказанная в этом вопросе, является полностью вымышленной и придумана исключительно с целью ознакомления.

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

Твое задание:

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

Входные данные:

Строка стрелок, как указано выше. Если вы хотите, стрелки могут заменить другие символы, но не забудьте указать, что вы делаете это в своем ответе. Все тестовые случаи используют стрелки как обычно.

Выход:

Строка стрелок (или ваших эквивалентных символов), которые доставят робота к желаемому месту назначения максимально эффективно.

Тестовые случаи:

Обратите внимание, что предлагаемые решения являются только возможностями, и что другие решения могут быть действительными.

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

Подсчет очков:

Память робота ограничена, поэтому ваша программа должна иметь минимально возможное количество байтов.


Поскольку на входе робот оказывается именно там, где он стартовал, поэтому не требуется никаких команд, чтобы перемещать его туда максимально эффективно.
Грифон - Восстановить Монику

О, неправильно прочитал строку. Виноват.
JungHwan Мин

Запрос теста ^<^^<^^<^^^^-> >^^>^?
ЮнгХван Мин

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

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

Ответы:


9

Retina , 103 74 71 байт

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

Попробуйте онлайн! Ссылка включает в себя тестовые случаи. Объяснение:

<
>>>

Поворот налево превращается в тройной поворот направо.

+`(>(\^*>){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

Установите jна 0 и установите 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

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

Попробуйте онлайн!

Принимает строку в качестве входных данных и выводит кратчайший путь, по которому будет осуществляться ввод.


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


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

Используйте t&3вместо того, t%4потому что это работает с отрицательным, tтак что вы можете удалить 4+и (). (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) вместо (<, ^,>), так как OP разрешил это, а также изменив мою систему координат, чтобы я мог уменьшить вычисление расстояния.

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

оповещения: >^^>^

Робот с реверсом был бы полезен.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.