Gdzie leci statek kosmiczny?

15

Na podstawie pomysłu zasugerowanego przez Zgarba .

Statek kosmiczny porusza się po zwykłej siatce 3D. Komórki siatki są indeksowane liczbami całkowitymi w prawym układzie współrzędnych xyz . Statkiem rozpoczyna się od początku, wskazując po dodatniej x osi, przy czym dodatni z oś skierowaną do góry.

Statek kosmiczny będzie latał trajektorią określoną przez niepustą sekwencję ruchów. Każdy ruch jest albo F(w górę), co powoduje, że statek kosmiczny przesuwa się o jedną komórkę w kierunku, w którym jest skierowany, lub o jeden z sześciu obrotów UDLRlr. Odpowiada to skokowi, odchyleniu i przewróceniu w następujący sposób:

PYR
Dzięki Zgarbowi za stworzenie diagramu.

  • Up i Dwłasne zmieniają skok statku kosmicznego o 90 stopni (gdzie kierunek odpowiada ruchowi nosa statku kosmicznego).
  • Left i Right zmieniają odchylenie statku kosmicznego o 90 stopni. Są to zwykłe skręty w lewo i prawo.
  • left i right to ruchy toczenia o 90 stopni, których kierunek wskazuje, które skrzydło porusza się w dół.

Pamiętaj, że należy je zawsze interpretować w stosunku do statku kosmicznego, aby odpowiednie osie obracały się wraz z nim.

Z matematycznego punktu widzenia statek kosmiczny początkowo znajduje się w pozycji (0, 0, 0), wskazując wzdłuż (1, 0, 0)wektora, (0, 0, 1)skierowany w górę. Obroty odpowiadają następującym matrycom zastosowanym w układzie współrzędnych:

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 )

Powinieneś wyprowadzić ostateczną pozycję statku kosmicznego jako trzy liczby całkowite x , y , z . Dane wyjściowe mogą być trzema oddzielnymi liczbami całkowitymi lub listą lub ciągiem je zawierającym. Mogą być w dowolnej spójnej kolejności, o ile ją określisz.

Możesz napisać program lub funkcję, pobierając dane wejściowe przez STDIN (lub najbliższą alternatywę), argument wiersza poleceń lub argument funkcji i wypisując wynik przez STDOUT (lub najbliższą alternatywę), wartość zwracaną funkcji lub parametr funkcji (wyjściowej).

Obowiązują standardowe zasady .

Przypadki testowe

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)

Przykład działał

Oto pośrednie etapy UFLrRFLRLRprzypadku testowego. Tutaj wszystkie pośrednie współrzędne i wektory kierunkowe są podane w początkowym globalnym układzie współrzędnych (w przeciwieństwie do jednego lokalnego dla statku kosmicznego):

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)
Martin Ender
źródło
Wyzwanie to uogólnienie 3D tego pomniejszenia, pomniejszone o część skrzyżowania.
orlp
Dlaczego 2! = 2, 3! = -1, 4! = 0! = -4, 1! = -3
nazwa_użytkownika.ak
@ username.ak Nie sądzę, że rozumiem pytanie. Co pan myśli?
Martin Ender
@Martin Büttner, mówię, dlaczego obrót o 180 stopni nie jest taki sam jak -180, 270 nie jest taki sam jak -90 itd.
username.ak
@ nazwa_użytkownika.ak to nie jest?
Martin Ender

Odpowiedzi:

3

MATL , 76 75 bajtów

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

Działa to w aktualnej wersji (12.1.1) języka.

Edycja (4 kwietnia 2016 r.): Zachowanie funkcji vzmieniło się w wersji 15.0.0 języka. Aby uruchomić powyższy kod, usuń pierwszy vi zastąp drugi 3$v. Poniższy link zawiera tę modyfikację.

Wypróbuj online !

Wyjaśnienie

Stan statku można opisać za pomocą dwóch zmiennych:

  • pozycja: wektor 3x1
  • orientacja: matryca 3x3 z zakumulowanym obrotem, gdzie „zakumulowany” oznacza powtarzany iloczyn macierzy.

Trzecią zmienną byłby kierunek, w którym statek jest zwrócony, ale nie jest to konieczne, ponieważ można go uzyskać jako kierunek początkowy (wektor kolumny [ 1;0;0]) razy bieżąca orientacja; to znaczy pierwsza kolumna orientacji.

Te dwie zmienne stanu są przechowywane na stosie i są aktualizowane z każdą literą. Każda z liter ULlDRrzwielokrotnia macierz orientacji przez jedną z sześciu macierzy obrotu, aby zaktualizować orientację. Litera Fdodaje bieżącą pozycję plus pierwszą kolumnę macierzy orientacji.

Sześć macierzy obrotu tworzy się w następujący sposób: pierwszy jest wprowadzany bezpośrednio; druga i trzecia to przesunięcia kołowe poprzedniej; a pozostałe trzy to transponowane wersje pozostałych.

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
Luis Mendo
źródło
1

Oktawa, 175 bajtów

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

Wersja do odczytu:

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
Rainer P.
źródło
Ładne użycie dynamicznych nazw pól!
Luis Mendo,
2
„Wersja czytelna [potrzebne źródło]”;)
trichoplax
0

ES6, 265 259 bajtów

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]

Objaśnienie: Zwykle w celu obliczenia kierunku statku kosmicznego ułożyłbyś wszystkie obroty razem, a następnie dla każdego ruchu skomponowałbyś wynik do wektora jednostki F = (1, 0, 0)(lub, po prostu, wyodrębnił pierwszą kolumnę macierzy). Na przykład FFrlFULULF => F + F + r⋅l⋅F + r⋅l⋅U⋅L⋅L⋅L⋅F. Ponieważ mnożenie macierzy jest asocjacyjne, języki z wbudowanym mnożeniem macierzy mogą oczywiście obliczać iloczyn częściowy r⋅l⋅U⋅L⋅L⋅Lwraz z upływem czasu, mnożąc przez to, Fco konieczne, aby utworzyć warunki, które są następnie sumowane. Niestety nie mam tego luksusu, więc najtańszą opcją jest obliczenie każdego terminu w powyższym wyrażeniu osobno, zaczynając od Fi pracując wstecz. W tym celu potrzebuję listy dla każdego wystąpienia Fwszystkich obrotów do tego momentu. Robię to za pomocąreplacez $`więc muszę również zaznaczyć początek i koniec każdego terminu na liście, aby móc zignorować resztę ciągu. Nieznacznie nie golfista:

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
Neil
źródło