Відносна проти абсолютного


17

Якщо хтось, що стоїть на півночі в точці A в цій сітці, бажає вказувати наступні зелені шляхи (так як вони можуть слідувати лише лінії сітки) до точки B, ви можете сказати їм:

Іди North, North, West, East, East, South, East, East.

або рівнозначно

Іди Forward, Forward, Left, Back, Forward, Right, Left, Forward.
(Якщо команда Праворуч , Ліворуч чи Назад неявно означає поворот у цьому напрямку, тоді йдіть вперед.)

Шлях від А до В

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

Якщо аргументом є рядок літер NSEW, поверніть еквівалентні відносні напрямки.
наприклад, f("NNWEESEE")повертає рядок FFLBFRLF.

Якщо аргументом є рядок літер FBLR, поверніть еквівалентні абсолютні напрямки.
наприклад, f("FFLBFRLF")повертає рядок NNWEESEE.

Порожня рядок поступається собою. Не припускайте жодних інших вхідних справ.

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

Виграє найкоротший код у байтах .


Чи припускаємо ми, що людина завжди починає головою, зверненою до Півночі? Таким чином, у відносному відношенні, щоб піти на Схід, це вимагатиме від нього повернути праворуч, а не просто говорити Вперед
оптимізатор

@Optimizer Так, північ. І так, для вашого іншого пункту. 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. ";
}

6

C ++, 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змінна. Я спробував переставити код, щоб повністю його усунути, але це здається неможливим ...

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

@Optimizer не більше. І сподіваючись скоротитись ще більше.
edc65

Що && oв кінці означає?
bebe

2
@bebe функція map повертає масив, всередині нього як побічний ефект я заповнюю рядок 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'⍳⍵]}

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

Іти, 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Функція знаходить індекс в межах двох легенди.

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