Para onde vai a nave espacial?

15

Baseado em uma idéia sugerida por Zgarb .

Uma nave espacial está se movendo em torno de uma grade 3D regular. As células da grade são indexadas com números inteiros em um sistema de coordenadas destro, xyz . A nave espacial começa na origem, apontando ao longo do x positivo eixo , com o eixo z positivo apontando para cima.

A nave espacial voará ao longo de uma trajetória definida por uma sequência não vazia de movimentos. Cada movimento é F(para a frente), o que faz a nave espacial mover uma célula na direção em que está virada, ou uma das seis rotações UDLRlr. Corresponde a pitch, yaw e roll da seguinte maneira:

PYR
Obrigado ao Zgarb por criar o diagrama.

  • Upe Dpróprio alteram o tom da nave espacial em 90 graus (onde a direção corresponde ao movimento do nariz da nave espacial).
  • Left e Right mudam a guinada da nave espacial em 90 graus. São apenas curvas regulares à esquerda e à direita.
  • left e right são movimentos de rolagem de 90 graus, em que a direção indica qual asa se move para baixo.

Observe que eles sempre devem ser interpretados em relação à nave espacial, para que os eixos relevantes girem junto com ela.

Em termos matemáticos, a nave espacial está inicialmente na posição (0, 0, 0), apontando ao longo do (1, 0, 0)vetor e (0, 0, 1)apontando para cima. As rotações correspondem às seguintes matrizes aplicadas ao sistema de coordenadas:

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 )

Você deve exibir a posição final da nave espacial como três números inteiros x , y , z . A saída pode ser três números inteiros separados ou uma lista ou sequência que os contenha. Eles podem estar em qualquer ordem consistente, desde que você o especifique.

Você pode escrever um programa ou função, recebendo entrada via STDIN (ou alternativa mais próxima), argumento da linha de comando ou argumento da função e exibindo o resultado via STDOUT (ou alternativa mais próxima), valor de retorno da função ou parâmetro da função (saída).

Aplicam-se as regras de padrão .

Casos de teste

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)

Exemplo trabalhado

Aqui estão as etapas intermediárias do UFLrRFLRLRcaso de teste. Aqui, todas as coordenadas intermediárias e vetores de direção são dados no sistema de coordenadas global inicial (em oposição a um local da nave espacial):

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
fonte
Este desafio é uma generalização 3D deste , menos a parte da interseção.
orlp
Por que 2! = 2, 3! = -1, 4! = 0! = -4, 1! = -3
username.ak
@ username.ak Acho que não entendi a pergunta. A que você se refere?
Martin Ender
@ Martin Büttner, eu digo por 180 graus de rotação não é o mesmo que -180, 270 não é o mesmo que -90 etc
username.ak
@ username.ak não é?
Martin Ender

Respostas:

3

MATL , 76 75 bytes

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

Isso funciona na versão atual (12.1.1) do idioma.

Editar (4 de abril de 2016): O comportamento da função v foi alterado no release 15.0.0 do idioma. Para executar o código acima, remova o primeiro ve substitua o segundo 3$v. O link a seguir inclui essa modificação.

Experimente online !

Explicação

O estado do navio pode ser descrito em termos de duas variáveis:

  • posição: vetor 3x1
  • orientação: matriz 3x3 com rotação acumulada , onde "acumulado" significa produto matricial repetido.

Uma terceira variável seria a direção em que o navio está voltado, mas isso não é necessário, porque pode ser obtido como a direção inicial (vetor da coluna [1;0;0] ) vezes a orientação atual; isto é, a primeira coluna da orientação.

Essas duas variáveis ​​de estado são mantidas na pilha e atualizadas a cada letra. Cada uma das letras ULlDRrmultiplica a matriz de orientação por uma das seis matrizes de rotação para atualizar a orientação. Carta Fadiciona a posição atual mais a primeira coluna da matriz de orientação.

As seis matrizes de rotação são criadas da seguinte forma: primeiro é introduzido diretamente; o segundo e o terceiro são turnos circulares do anterior; e os três restantes são versões transpostas dos outros.

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
fonte
1

Oitava, 175 bytes

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

Versão legível:

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.
fonte
Bom uso de nomes de campos dinâmicos!
Luis Mendo
2
"Versão legível [citação necessária]";)
trichoplax 12/02/16
0

ES6, 265 259 bytes

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]

Explicação: Normalmente, para calcular a direção da nave espacial que você iria compor todas as rotações juntos, e, em seguida, para cada movimento que você iria compor o resultado para o vetor unitário com então eu também precisa marcar o início eo fim de cada termo na lista para que eu posso ignorar o resto da string. Ligeiramente não destruído:F = (1, 0, 0) (ou, mais simplesmente, extrairia a primeira coluna da matriz). Por exemplo FFrlFULULF => F + F + r⋅l⋅F + r⋅l⋅U⋅L⋅L⋅L⋅F,. Como a multiplicação de matrizes é associativa, as linguagens com multiplicação de matrizes embutidas podem obviamente computar o produto parcial à r⋅l⋅U⋅L⋅L⋅Lmedida que avançam, multiplicandoF necessário para produzir os termos que são então adicionados juntos. Infelizmente, eu não tenho esse luxo, então a opção mais barata é calcular cada termo na expressão acima separadamente, começandoF e retornando. Para isso, preciso de uma lista para cada uma das ocorrências Fde todas as rotações até esse ponto. Eu faço isso usandoreplace$`

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
fonte