Куда уходит космический корабль?

15

Основано на идее, предложенной Згарбом .

Космический корабль движется вокруг обычной трехмерной сетки. Ячейки сетки индексируются целыми числами в правой системе координат xyz . Космический корабль начинается в начале координат, указывая вдоль положительной оси x , с положительным z ось направлена ​​вверх.

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

PYR
Спасибо Згарбу за создание диаграммы.

  • Up и Dсобственной изменяют угол наклона космического корабля на 90 градусов (где направление соответствует движению носа космического корабля).
  • LEft и ight Rизменяют угол наклона космического корабля на 90 градусов. Они просто обычные левый и правый повороты.
  • left и ight r- 90-градусное вращение, где направление указывает, какое крыло движется вниз.

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

В математическом плане космический корабль изначально находится в положении (0, 0, 0), направленном вдоль (1, 0, 0)вектора, с (0, 0, 1)указанием вверх. Вращения соответствуют следующим матрицам, примененным к системе координат:

U = ( 0  0 -1     D = ( 0  0  1
      0  1  0           0  1  0
      1  0  0 )        -1  0  0 )

L = ( 0 -1  0     R = ( 0  1  0
      1  0  0          -1  0  0
      0  0  1 )         0  0  1 )

l = ( 1  0  0     r = ( 1  0  0
      0  0  1           0  0 -1
      0 -1  0 )         0  1  0 )

Вы должны вывести конечную позицию космического корабля в виде трех целых чисел x , y , z . Выходные данные могут быть тремя отдельными целыми числами или списком или строкой, содержащей их. Они могут быть в любом последовательном порядке, если вы укажете это.

Вы можете написать программу или функцию, принимая ввод через STDIN (или ближайшую альтернативу), аргумент командной строки или аргумент функции и выводя результат через STDOUT (или ближайшую альтернативу), возвращаемое значение функции или параметр функции (out).

Применяются стандартные правила .

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

F                                                   => (1, 0, 0)
FDDF                                                => (0, 0, 0)
FDDDF                                               => (1, 0, 1)
LrDDlURRrr                                          => (0, 0, 0)
UFLrRFLRLR                                          => (1, 0, 1)
FFrlFULULF                                          => (3, 0, -1)
LLFRLFDFFD                                          => (-2, 0, -2)
FrrLFLFrDLRFrLLFrFrRRFFFLRlFFLFFRFFLFlFFFlUFDFDrFF  => (1, 5, 7)
FUrRLDDlUDDlFlFFFDFrDrLrlUUrFlFFllRLlLlFFLrUFlRlFF  => (8, 2, 2)
FFLrlFLRFFFRFrFFFRFFRrFFFDDLFFURlrRFFFlrRFFlDlFFFU  => (1, 2, -2)
FLULFLFDURDUFFFLUlFlUFLFRrlDRFFFLFUFrFllFULUFFDRFF  => (-3, -2, -3)

Работал пример

Вот промежуточные этапы UFLrRFLRLRтеста. Здесь все промежуточные координаты и векторы направления задаются в исходной глобальной системе координат (в отличие от одного локального для космического корабля):

Cmd.  Position    Forward     Up
      ( 0, 0, 0)  ( 1, 0, 0)  ( 0, 0, 1)
U     ( 0, 0, 0)  ( 0, 0, 1)  (-1, 0, 0)
F     ( 0, 0, 1)  ( 0, 0, 1)  (-1, 0, 0)
L     ( 0, 0, 1)  ( 0, 1, 0)  (-1, 0, 0)
r     ( 0, 0, 1)  ( 0, 1, 0)  ( 0, 0, 1)
R     ( 0, 0, 1)  ( 1, 0, 0)  ( 0, 0, 1)
F     ( 1, 0, 1)  ( 1, 0, 0)  ( 0, 0, 1)
L     ( 1, 0, 1)  ( 0, 1, 0)  ( 0, 0, 1)
R     ( 1, 0, 1)  ( 1, 0, 0)  ( 0, 0, 1)
L     ( 1, 0, 1)  ( 0, 1, 0)  ( 0, 0, 1)
R     ( 1, 0, 1)  ( 1, 0, 0)  ( 0, 0, 1)
Мартин Эндер
источник
Этот вызов является трехмерным обобщением этого , за исключением части пересечения.
orlp
Почему 2! = 2, 3! = -1, 4! = 0! = -4, 1! = -3
username.ak
@ username.ak Я не думаю, что понимаю вопрос. Что ты имеешь в виду?
Мартин Эндер
@ Мартин Бюттнер, я говорю, почему вращение на 180 градусов не то же самое, что -180, 270 не то же самое, что -90 и т. Д.
username.ak
@ username.ak это не так?
Мартин Эндер

Ответы:

3

MATL , 76 75 байт

FFF!3Xyj"FFT_FTFv4BvtFT_YStTF_YS3:"3$y!]6$Xh@'ULlDRr'4#mt?X)Y*}xxt1Z)b+w]]x

Это работает в текущей версии (12.1.1) языка.

Изменить (4 апреля 2016 г.): Поведение функции vизменилось в выпуске 15.0.0 языка. Чтобы запустить приведенный выше код, удалите первое vи замените второе 3$v. Следующая ссылка включает в себя эту модификацию.

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

объяснение

Состояние корабля можно описать с помощью двух переменных:

  • положение: вектор 3х1
  • ориентация: матрица 3х3 с накопленным вращением, где «накопленный» означает повторное матричное произведение.

Третья переменная - это направление, в котором стоит корабль, но в этом нет необходимости, поскольку его можно получить как начальное направление (вектор столбца [ 1;0;0]), умноженное на текущую ориентацию; то есть первый столбец ориентации.

Эти две переменные состояния хранятся в стеке и обновляются с каждой буквой. Каждая из букв ULlDRrумножает матрицу ориентации на одну из шести матриц вращения, чтобы обновить ориентацию. ПисьмоF добавляет текущую позицию плюс первый столбец матрицы ориентации.

Шесть матриц вращения создаются следующим образом: первая вводится напрямую; второе и третье - круговые сдвиги предыдущего; а остальные три являются транспонированными версиями других.

FFF!             % 3x1 vector [0;0;0]: initial position
3Xy              % 3x3 identity matrix: initial orientation
j                % input string
"                % for-each character in that string
  FFT_FTFv4Bv    %   rotation matrix for U: defined directly
  tFT_YS         %   rotation matrix for L: U circularly shifted to the left
  tTF_YS         %   rotation matrix for l: L circularly shifted down
  3:"            %   repeat three times
    3$y!         %     copy third matrix from top and transpose
  ]              %   end loop. This creates rotation matrices for D, R, r
  6$Xh           %   pack the 6 matrices in a cell array
  @              %   push current character from the input string
  'ULlDRr'4#m    %   this gives an index 0 for F, 1 for U, 2 for L, ..., 6 for r
  t?             %   if non-zero: update orientation
    X)           %     pick corresponding rotation matrix
    Y*           %     matrix product
  }              %   else: update position
    xx           %     delete twice (index and rotation matrix are not used here)
    t1Z)         %     duplicate orientation matrix and take its first column
    b+           %     move position vector to top and add
    w            %     swap the two top-most elements in stack
  ]              %   end if
]                % end for-each
x                % delete orientation matrix
                 % implicitly display position vector
Луис Мендо
источник
1

Октава, 175 байт

function p=s(i)m.U=[0,0,-1;0,1,0;1,0,0];m.D=m.U';m.L=[0,-1,0;1,0,0;0,0,1];m.R=m.L';m.l=flip(flip(m.L),2);m.r=m.l';a=m.F=eye(3);p=[0;0;0];for c=i p+=(a*=m.(c))*[c=='F';0;0];end

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

function p=s(i)
  m.U=[0,0,-1;0,1,0;1,0,0];
  m.D=m.U';
  m.L=[0,-1,0;1,0,0;0,0,1];
  m.R=m.L';
  m.l=flip(flip(m.L),2);
  m.r=m.l';
  a=m.F=eye(3);
  p=[0;0;0];
  for c=i p+=(a*=m.(c))*[c=='F';0;0];
end
Райнер П.
источник
Хорошее использование динамических имен полей!
Луис Мендо
2
"Читаемая версия [цитата нужна]";)
trichoplax
0

ES6, 265 259 байт

s=>[...s.replace(/F/g,"f$`s")].reverse().map(e=>d={U:(x,y,z)=>[-z,y,x],D:(x,y,z)=>[z,y,-x],L:(x,y,z)=>[-y,x,z],R:(x,y,z)=>[y,-x,z],r:(x,y,z)=>[x,-z,y],l:(x,y,z)=>[x,z,-y],F:(...d)=>d,f:(x,y,z)=>[a+=x,b+=y,c+=z]),s:_=>[1,0,0]}[e](...d),d=[1,0,a=b=c=0])&&[a,b,c]

Объяснение: Обычно, чтобы рассчитать направление космического корабля, вы должны составить все повороты вместе, а затем для каждого движения вы будете составлять результат для единичного вектора F = (1, 0, 0)(или, проще говоря, извлечь первый столбец матрицы). Так , например, FFrlFULULF => F + F + r⋅l⋅F + r⋅l⋅U⋅L⋅L⋅L⋅F. Поскольку матричное умножение является ассоциативным, языки со встроенным умножением матриц, очевидно, могут вычислять частичное произведение по r⋅l⋅U⋅L⋅L⋅Lмере их продвижения, умножаясь на , по Fмере необходимости, для получения терминов, которые затем складываются. К сожалению, у меня нет такой роскоши, поэтому самый дешевый вариант - вычислить каждый термин в вышеприведенном выражении отдельно, начиная с Fи возвращаясь. Для этого мне нужен список для каждого вхождения Fвсех вращений до этой точки. Я делаю это используяreplace с, $`поэтому мне также нужно отметить начало и конец каждого термина в списке, чтобы я мог игнорировать остальные строки. Слегка разгульный

s=>[... // split the string into separate operations
    s.replace(/F/g,"f$`s")] // For each 'F', wrap the operations up to that point
  .reverse() // Play all the operations in reverse order
  .map(e=>d= // Update the direction for each operation
    { // set of operations
      U:(x,y,z)=>[-z,y,x], // Up
      D:(x,y,z)=>[z,y,-x], // Down
      L:(x,y,z)=>[-y,x,z], // Left turn
      R:(x,y,z)=>[y,-x,z], // Right turn
      r:(x,y,z)=>[x,-z,y], // right roll
      l:(x,y,z)=>[x,z,-y], // left roll
      F:(...d)=>d, // does nothing, `s` and `f` do the work now
      f:(x,y,z)=>[a+=x,b+=y,c+=z], // do the move
      s:_=>[1,0,0] // back to start
    }[e](...d), // apply the operation to the current direction
    d=[1,0,a=b=c=0] // initialise variables
  )&&[a,b,c] // return result
Нил
источник