Относительный против Абсолюта

17

Если кто-то, смотрящий на север в точке A в этой сетке, хотел, чтобы направления следовали по зеленой траектории (поскольку они могут следовать только по линиям сетки) до точки B, вы можете сказать им:

Go North, North, West, East, East, South, East, East.

или эквивалентно

Go Forward, Forward, Left, Back, Forward, Right, Left, Forward.
(Если команда « Вправо» , « Влево» или « Назад» неявно означает поворот в этом направлении, а затем движение вперед.)

Путь от А до Б

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

Если аргумент является строкой букв NSEW, вернуть эквивалентные относительные направления.
например, f("NNWEESEE")возвращает строку FFLBFRLF.

Если аргумент является строкой букв FBLR, вернуть эквивалентные абсолютные направления.
например, f("FFLBFRLF")возвращает строку NNWEESEE.

Пустая строка возвращает себя. Не предполагайте никаких других входных случаев.

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

Самый короткий код в байтах побеждает.

Кальвин Хобби
источник
Предполагаем ли мы, что человек всегда начинает с головы лицом к северу? Таким образом, в относительном выражении, чтобы идти на восток, ему потребуется повернуть направо, а не просто сказать «Вперед»
Оптимизатор
@ Оптимизатор Да, север. И да, с другой стороны. Rравняется Eв начале.
Увлечения Кэлвина
1
Ура! Вы изменили свою фотографию, чтобы подтвердить то, что я всегда думал!
Джастин
4
Вы снова зацепили PPCG? ;)
Мартин Эндер
4
@ MartinBüttner Либо так, либо я очень хорошо маскирую свои домашние проблемы. ;)
Увлечения Кэлвина

Ответы:

6

CJam, 57 53 49

{"NESW""FRBL"_3$&!!:Q$:R^^f#0\{{+0\}Q*_@-R=\}%);}

Предыдущая версия

{"NESW""FRBL"_3$0=#W>:Q{\}*:R;f#0\{{+0\}Q*_@-R=\}%);}

Пример:

{"NESW""FRBL"_3$0=#W>:Q{\}*:R;f#0\{{+0\}Q*_@-R=\}%);}:T;
"NNWEESEE"T
N
"FFLBFRLF"T

Выход:

FFLBFRLF
NNWEESEE

Как это устроено

{
  "NESW""FRBL"             " Push the two strings. ";
  _3$0=#W>                 " Check if the first character is in FRBL. ";
  :Q                       " Assign the result to Q. ";
  {\}*                     " Swap the two strings if true. ";
  :R;                      " Assign the top string to R and discard it. ";
  f#                       " Find each character of the input in the string. ";
  0\                       " Push a 0 under the top of the stack. ";
  {                        " For each item (index of character): ";
    {                      " If Q: ";
      +0\                  " A B -> 0 (A+B) ";
    }Q*
    _@-                    " C D -> D (D-C) ";
    R=                     " E -> E-th character in R ";
    \                      " Swap the top two items. ";
  }%
  );                       " Discard the last item in the list. ";
}
jimmy23013
источник
6

С ++, 99 97

Следующее форматируется как лямбда-выражение. Он принимает один char*аргумент и перезаписывает его.

[](char*s){for(int d=0,n=0,c=*s*9%37&4;*s;d+=n)c?n=*s%11/3-d:n+=*s%73%10,*s++="NESWFRBL"[c|n&3];}

Для тех, кто не знаком с этой функцией (как я 1 час назад), используйте ее следующим образом:

#include <iostream>

int main()
{
    char s[] = "NNWEESEE";
    auto x = [](char*s){for(int d=0,n=0,c=*s*9%37&4;*s;d+=n)c?n=*s%11/3-d:n+=*s%73%10,*s++="NESWFRBL"[c|n&3];};

    x(s); // transform from absolute to relative
    std::cout << s << '\n';

    x(s); // transform from relative to absolute
    std::cout << s << '\n';
}

Некоторые объяснения:

  • При использовании кода наподобие flag ? (x = y) : (x += z)второй пары скобок требуется в C. Поэтому я использовал C ++ вместо этого!
  • C ++ требует указания возвращаемого типа для функции. Если я не использую лямбда-выражение, то есть! Дополнительный бонус: мне не нужно тратить 1 символ на название функции.
  • Код *s*9%37&4тестирует первый байт; результат 4, если он один из NESW; 0 иначе
  • Код *s%11/3преобразует байты NESWв 0, 1, 2, 3
  • Код *s%73%10преобразует байты FRBLв 0, 9, 6, 3 (это 0, 1, 2, 3 по модулю 4)
  • При преобразовании относительных направлений в абсолютные, мне не нужна dпеременная. Я попытался изменить код, чтобы полностью устранить его, но это кажется невозможным ...
anatolyg
источник
1
Мне очень нравится, как вы конвертируете буквы в цифры. :)
Эмиль
6

JavaScript (E6) 84 86 88 92 104

Редактировать: используя & вместо%, другой приоритет оператора (меньше скобок) и лучше работает с отрицательными числами
Edit2: | вместо + снова укажите приоритет, -2. Спасибо DocMax
Edit3: понимание массива на 2 символа короче, чем map (), для строк

F=p=>[o+=c[d=n,n=c.search(i),n<4?4|n-d&3:n=n+d&3]for(i of n=o='',c='NESWFRBL',p)]&&o

Тест в консоли FireFox / FireBug

console.log(F('NNWEESEE'),F('FFLBFRLF'))

Выход

FFLBFRLF NNWEESEE
edc65
источник
@ Оптимизатор больше нет. И в надежде сжаться еще больше.
edc65
Что && oв конце значит?
bebe
2
@bebe функция карты возвращает массив, внутри него, в качестве побочного эффекта, я заполняю o строку, которую я должен вернуть. array && valueоценивать valueкак любой массив оцениватьtruthy
edc65
1
В заключение! Я смотрел на этот , так как он ударил 88. Если меня не хватает чего - то, вы можете заменить 4+(n-d&3)с 4|n-d&3и сохранить 2 символов.
DocMax
4

APL, 72

{^/⍵∊A←'NESW':'FRBL'[1+4|-2-/4,3+A⍳⍵]⋄A[1+4|+\'RBLF'⍳⍵]}

Если конфигурации переводчика могут быть изменены без штрафа, то оценка 66 , изменив ⎕IOна 0:

{^/⍵∊A←'NESW':'FRBL'[4|-2-/0,A⍳⍵]⋄A[4|+\'FRBL'⍳⍵]}
TwiNight
источник
3

Питон, 171 139

Не так близко, как другие решения, но я думаю, что это должно быть относительно хорошо для того, что можно сделать с помощью Python:

def f(i):a,b='NWSE','FLBR';I=map(a.find,'N'+i);return''.join((b[I[k+1]-I[k]],a[sum(map(b.find,i)[:k+1])%4])[-1in I]for k in range(len(i)))

Расширенная версия для немного лучшей читаемости:

def f(i):
    a, b = 'NWSE', 'FLBR'
    I = map(a.find,'N'+i)     # translate to numbers assuming abs. directions
    J = map(b.index,i)        # translate to numbers assuming rel. directions
    if not -1 in I:
        o = [b[I[k+1]-I[k]] for k in range(len(i))]    # rel. dir. is differences of abs. dir.
    else:
        o = [a[sum(J[:k+1])%4] for k in range(len(i))] # abs. dir. is sum of all rel. dir. so far
    return ''.join(o)
Эмиль
источник
1

Go, 201

type q string;func F(s q)q{d,z:=byte(0),make([]byte,len(s));for i,c:=range[]byte(s){if(c^4)*167%3<2{c=c*156%5;z[i],d="LBRF"[(d-c)%4],c-1;}else{c=(c^43)*3%7-1;d=(d+c)%4;z[i]="NESW"[d];};};return q(z);}

Читаемая версия:

func F(s string) string {
    d, z, R, A := 0, make([]byte, len(s)), "LBRFLBR", "NESW"
    for i, c := range []byte(s) {
        switch c {
        case 'N': c = R[d+3]; d = 0
        case 'E': c = R[d+2]; d = 1
        case 'S': c = R[d+1]; d = 2
        case 'W': c = R[d]; d = 3
        case 'F': c = A[d]
        case 'R': d = (d + 1) % 4; c = A[d]
        case 'B': d = (d + 2) % 4; c = A[d]
        case 'L': d = (d + 3) % 4; c = A[d]
        }
        z[i] = c
    }
    return string(z)
}

Дэвид
источник
1

GNU sed, 356 байт

Задача требует простого преобразования потока символов. sed, редактор потоков - очевидный выбор языка ;-)

/[FRBL]/bx                                     # Jump to label x if relative
:y                                             # label y (start of abs->rel loop)
/[FRBL]$/q                                     # quit if string ends in rel char
s/(^|[FRBL])N/\1F/;ty                          # Substitute next abs char with
s/(^|[FRBL])E/\1R/;tr                          #     rel char, then jump to
s/(^|[FRBL])S/\1B/;tb                          #     relevant rotation label if
s/(^|[FRBL])W/\1L/;tl                          #     a match was found
by                                             # loop back to y
:r;y/NESW/WNES/;by                             # Rotation labels: transform then
:b;y/NESW/SWNE/;by                             #     loop back to y
:l;y/NESW/ESWN/;by
:x                                             # label x (start of rel->abs loop)
/^[NESW]/q                                     # quit if string starts w/ abs char
/F([NESW]|$)/s/F([NESW]|$)/N\1/                # Matches for each direction:
/R([NESW]|$)/y/NESW/ESWN/;s/R([NESW]|$)/E\1/   #     rotate, then substitute
/B([NESW]|$)/y/NESW/SWNE/;s/B([NESW]|$)/S\1/
/L([NESW]|$)/y/NESW/WNES/;s/L([NESW]|$)/W\1/
bx                                             # loop back to x

(Комментарии и пробелы удалены для целей подсчета очков в гольф)

Выход:

$ sed -rf absrel.sed <<< NNWEESEE
FFLBFRLF
$ sed -rf absrel.sed <<< FFLBFRLF
NNWEESEE
$ 

Объяснение:

Идея в том, что когда мы меняем систему отсчета, всегда существует прямое отображение между {N, E, S, W}и {F, R, B, L}.

В случае абсолютного и относительного мы работаем вперед по строке. Для каждого символа мы карта , {N, E, S, W}чтобы {F, R, B, L}, затем повернуть остальные [NESW]символы в соответствии с характером , мы просто отображенным, а затем перейти к следующему символу.

Для случая относительно абсолютного мы делаем обратное. Мы работаем в обратном направлении через строку, вращая все последующие [NESW]символы в соответствии с символом непосредственно перед. Тогда мы отображаем этот символ {N, E, S, W}к {F, R, B, L}, пока не дойдут до начала строки.

Цифровая травма
источник
0

Хаскелл, 224

import Data.Function
i=flip(\x->length.takeWhile(/=x))
r=['F','R','B','L']
a=['N','E','S','W']
f s@(x:_)|elem x a=map((r!!).(`mod`4).(4-))$zipWith((-)`on`(i a))('N':s)(s)|True=tail$map((a!!).(`mod`4)).scanl(+)(0)$map(i r) s

Это назначает числа вращения относительным направлениям и числа ориентации абсолютным направлениям, затем либо находит повороты между последовательными ориентациями, либо ориентации после последовательных вращений. iФункция находит индекс в пределах двух легенды.

archaephyrryx
источник