Куди відправляється космічний корабель?


15

На основі ідеї, запропонованої Згарбом .

Космічний корабель рухається навколо звичайної 3D-сітки. Осередки сітки індексуються цілими числами в правій системі координат, xyz . Космічний корабель починається з початку, вказуючи вздовж позитивної осі x , позитивна вісь z спрямована вгору.

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

PYR
Дякую Згарбу за створення діаграми.

  • Up і Dвласне змінюють крок космічного корабля на 90 градусів (де напрямок відповідає руху носа космічного корабля).
  • Left і я Rміняю позіхання космічного корабля на 90 градусів. Вони просто регулярні лівий і правий повороти.
  • left and right - це рухи кочення на 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)

Цей виклик є 3D узагальненням цього за вирахуванням частини перетину.
orlp

Чому 2! = 2, 3! = -1, 4! = 0! = -4, 1! = -3
ім'я користувача.ak

@ username.ak Я не думаю, що я розумію питання. На що ви маєте на увазі?
Мартін Ендер

@Martin Büttner, я кажу, чому обертання на 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. Наступне посилання включає цю зміну.

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

Пояснення

Стан корабля можна описати двома змінними:

  • положення: 3x1 вектор
  • орієнтація: 3x3 матриця з накопиченим обертанням, де "накопичена" означає повторний матричний продукт.

Третьою змінною буде напрямок, в якому судно стикається, але це не потрібно, оскільки воно може бути отримане як початковий напрямок (вектор стовпця [ 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.