Où va le vaisseau spatial?

15

Basé sur une idée suggérée par Zgarb .

Un vaisseau spatial se déplace autour d'une grille 3D régulière. Les cellules de la grille sont indexées avec des entiers dans un système de coordonnées droitier, xyz . Le vaisseau spatial commence à l'origine, pointant le long de l' axe x positif , l' axe z positif pointant vers le haut.

Le vaisseau spatial volera le long d'une trajectoire définie par une séquence de mouvements non vide. Chaque mouvement se fait soit F( ou vers l' intérieur) ce qui fait que le vaisseau spatial se déplace d'une cellule dans la direction de son orientation, ou l'une des six rotations UDLRlr. Cela correspond au tangage, au lacet et au roulis comme suit:

PYR
Merci à Zgarb d'avoir créé le diagramme.

  • Up et Dpropre modifient l'inclinaison du vaisseau spatial de 90 degrés (où la direction correspond au mouvement du nez du vaisseau spatial).
  • Left et Right modifient le lacet du vaisseau spatial de 90 degrés. Ce ne sont que des virages à gauche et à droite réguliers.
  • left et right sont des mouvements de roulement à 90 degrés, où la direction indique quelle aile se déplace vers le bas.

Notez que ceux-ci doivent toujours être interprétés par rapport au vaisseau spatial afin que les axes concernés tournent avec lui.

En termes mathématiques, le vaisseau spatial est initialement en position (0, 0, 0), pointant le long du (1, 0, 0)vecteur, (0, 0, 1)pointant vers le haut. Les rotations correspondent aux matrices suivantes appliquées au système de coordonnées:

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 )

Vous devez afficher la position finale du vaisseau spatial sous la forme de trois entiers x , y , z . La sortie peut être trois entiers distincts ou une liste ou une chaîne les contenant. Ils peuvent être dans n'importe quel ordre cohérent tant que vous le spécifiez.

Vous pouvez écrire un programme ou une fonction, en prenant une entrée via STDIN (ou l'alternative la plus proche), un argument de ligne de commande ou un argument de fonction et en sortant le résultat via STDOUT (ou l'alternative la plus proche), la valeur de retour de la fonction ou le paramètre de la fonction (out).

Les règles de standard s'appliquent.

Cas de test

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)

Exemple travaillé

Voici les étapes intermédiaires du UFLrRFLRLRcas de test. Ici, toutes les coordonnées intermédiaires et les vecteurs de direction sont donnés dans le système de coordonnées global initial (par opposition à un local du vaisseau spatial):

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
la source
Ce défi est une généralisation 3D de celui-ci , moins la partie intersection.
orlp
Pourquoi 2! = 2, 3! = -1, 4! = 0! = -4, 1! = -3
username.ak
@ username.ak Je ne pense pas avoir compris la question. A quoi faites-vous référence?
Martin Ender
@Martin Büttner, je dis pourquoi la rotation à 180 degrés n'est pas la même chose que -180, 270 n'est pas la même chose que -90, etc.
username.ak
@ nomutilisateur.ak n'est-ce pas?
Martin Ender

Réponses:

3

MATL , 76 75 octets

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

Cela fonctionne dans la version actuelle (12.1.1) de la langue.

Edit (4 avril 2016): Le comportement de la fonction va changé dans la version 15.0.0 du langage. Pour exécuter le code ci-dessus, supprimez le premier vet remplacez le second 3$v. Le lien suivant inclut cette modification.

Essayez-le en ligne !

Explication

L'état du navire peut être décrit en fonction de deux variables:

  • position: vecteur 3x1
  • orientation: matrice 3x3 avec rotation cumulée , où "accumulé" signifie produit matriciel répété.

Une troisième variable serait la direction dans laquelle le navire fait face, mais ce n'est pas nécessaire, car elle peut être obtenue en tant que direction initiale (vecteur de colonne [ 1;0;0]) multiplié par l'orientation actuelle; c'est-à-dire la première colonne de l'orientation.

Ces deux variables d'état sont conservées dans la pile et sont mises à jour avec chaque lettre. Chacune des lettres ULlDRrmultiplie la matrice d'orientation par l'une des six matrices de rotation pour mettre à jour l'orientation. La lettre Fajoute la position actuelle plus la première colonne de la matrice d'orientation.

Les six matrices de rotation sont créées comme suit: la première est introduite directement; les deuxième et troisième sont des décalages circulaires du précédent; et les trois autres sont des versions transposées des autres.

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
la source
1

Octave, 175 octets

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

Version lisible:

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.
la source
Belle utilisation des noms de champs dynamiques!
Luis Mendo
2
"Version lisible [citation nécessaire]";)
trichoplax
0

ES6, 265 259 octets

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]

Explication: Normalement, pour calculer la direction du vaisseau spatial, vous composeriez toutes les rotations ensemble, puis pour chaque mouvement, vous composeriez le résultat vers le vecteur unitaire F = (1, 0, 0)(ou plus simplement extraire la première colonne de la matrice). Par exemple, FFrlFULULF => F + F + r⋅l⋅F + r⋅l⋅U⋅L⋅L⋅L⋅F. Comme la multiplication matricielle est associative, les langages avec multiplication matricielle intégrée peuvent évidemment calculer le produit partiel au r⋅l⋅U⋅L⋅L⋅Lfur et à mesure, en multipliant par Fautant que nécessaire pour produire les termes qui sont ensuite additionnés. Malheureusement, je n'ai pas ce luxe, donc l'option la moins chère est de calculer chaque terme dans l'expression ci-dessus séparément, en commençant par Fet en revenant. Pour cela, j'ai besoin d'une liste pour chacune des occurrences Fde toutes les rotations jusqu'à ce point. Je le fais en utilisantreplaceavec $`donc je dois également marquer le début et la fin de chaque terme dans la liste afin que je puisse ignorer le reste de la chaîne. Légèrement non golfé:

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
la source