¿A dónde va la nave espacial?

15

Basado en una idea sugerida por Zgarb .

Una nave espacial se mueve alrededor de una cuadrícula 3D normal. Las celdas de la cuadrícula se indexan con números enteros en un sistema de coordenadas diestro, xyz . La nave espacial comienza en el origen, apuntando a lo largo del eje x positivo , con el eje z positivo apuntando hacia arriba.

La nave espacial volará a lo largo de una trayectoria definida por una secuencia de movimientos no vacía. Cada movimiento es F(hacia adelante), lo que hace que la nave espacial se mueva una celda en la dirección de su orientación, o una de las seis rotaciones UDLRlr. Esto corresponde a cabeceo, guiñada y balanceo de la siguiente manera:

PYR
Gracias a Zgarb por crear el diagrama.

  • Up y Down cambian el tono de la nave espacial en 90 grados (donde la dirección corresponde al movimiento de la nariz de la nave espacial).
  • Left y Right cambian el guiñada de la nave espacial en 90 grados. Son solo giros regulares a izquierda y derecha.
  • left y right son movimientos de balanceo de 90 grados, donde la dirección indica qué ala se mueve hacia abajo.

Tenga en cuenta que estos siempre deben interpretarse en relación con la nave espacial para que los ejes relevantes roten junto con ella.

En términos matemáticos, la nave espacial está inicialmente en posición (0, 0, 0), apuntando a lo largo del (1, 0, 0)vector, (0, 0, 1)apuntando hacia arriba. Las rotaciones corresponden a las siguientes matrices aplicadas al 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 )

Deberías mostrar la posición final de la nave espacial como tres enteros x , y , z . La salida puede ser tres enteros separados o una lista o cadena que los contiene. Pueden estar en un orden constante siempre que lo especifique.

Puede escribir un programa o función, tomando datos a través de STDIN (o la alternativa más cercana), argumento de línea de comandos o argumento de función y generando el resultado a través de STDOUT (o alternativa más cercana), valor de retorno de función o parámetro de función (out).

Se aplican reglas estándar de .

Casos de prueba

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)

Ejemplo trabajado

Aquí están los pasos intermedios del UFLrRFLRLRcaso de prueba. Aquí, todas las coordenadas intermedias y los vectores de dirección se dan en el sistema de coordenadas global inicial (en oposición a uno local de la 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
fuente
Este desafío es una generalización 3D de este , menos la parte de intersección.
orlp
¿Por qué 2! = 2, 3! = -1, 4! = 0! = -4, 1! = -3
username.ak
@ username.ak No creo que entienda la pregunta. ¿A qué te refieres?
Martin Ender
@ Martin Büttner, digo por qué 180 grados de rotación no es lo mismo que -180, 270 no es lo mismo que -90, etc.
username.ak
@ username.ak ¿no es así?
Martin Ender

Respuestas:

3

MATL , 76 75 bytes

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

Esto funciona en la versión actual (12.1.1) del lenguaje.

Editar (4 de abril de 2016): el comportamiento de la función vha cambiado en la versión 15.0.0 del lenguaje. Para ejecutar el código anterior, elimine el primero vy reemplace el segundo 3$v. El siguiente enlace incluye esta modificación.

Pruébalo en línea !

Explicación

El estado del barco se puede describir en términos de dos variables:

  • posición: vector 3x1
  • orientación: matriz 3x3 con la rotación acumulada , donde "acumulado" significa producto de matriz repetido.

Una tercera variable sería la dirección en la que se enfrenta la nave, pero eso no es necesario, ya que puede obtenerse como la dirección inicial (vector de columna [ 1;0;0]) multiplicada por la orientación actual; es decir, la primera columna de la orientación.

Estas dos variables de estado se mantienen en la pila y se actualizan con cada letra. Cada una de las letrasULlDRr multiplica la matriz de orientación por una de las seis matrices de rotación para actualizar la orientación. Letter Fagrega la posición actual más la primera columna de la matriz de orientación.

Las seis matrices de rotación se crean de la siguiente manera: primero se introduce directamente; segundo y tercero son desplazamientos circulares del anterior; y los tres restantes son versiones transpuestas de los otros.

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

Octava, 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

Versión legible:

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.
fuente
Buen uso de nombres de campo dinámico!
Luis Mendo
2
"Versión legible [cita requerida]";)
trichoplax
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]

Explicación: Normalmente, para calcular la dirección de la nave espacial, compondría todas las rotaciones juntas, y luego, para cada movimiento, compondría el resultado en el vector unitario F = (1, 0, 0)(o simplemente extraería la primera columna de la matriz). Por ejemplo, FFrlFULULF => F + F + r⋅l⋅F + r⋅l⋅U⋅L⋅L⋅L⋅F. Dado que la multiplicación matricial es asociativa, los lenguajes con multiplicación matricial incorporada obviamente pueden calcular el producto parcial a r⋅l⋅U⋅L⋅L⋅Lmedida que avanzan, multiplicándose según Fsea ​​necesario para producir los términos que luego se suman. Desafortunadamente, no tengo ese lujo, por lo que la opción más barata es calcular cada término en la expresión anterior por separado, comenzando Fy trabajando hacia atrás. Para eso, necesito una lista para cada una de las ocurrencias Fde todas las rotaciones hasta ese punto. Hago esto usandoreplacecon, $`así que también necesito marcar el inicio y el final de cada término en la lista para poder ignorar el resto de la cadena. Ligeramente no 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
fuente