Mouvement sur une grille hexagonale

15

Étant donné l'entrée d'une série de caractères représentant des mouvements sur une grille hexagonale, sortez les coordonnées finales du «pointeur».

Nos hexagones seront numérotés ainsi (imaginez une grille rectangulaire avec chaque colonne impaire légèrement décalée vers le bas):

  _____         _____         _____         _____
 /     \       /     \       /     \       /     \
/ -3,-2 \_____/ -1,-2 \_____/  1,-2 \_____/  3,-2 \
\       /     \       /     \       /     \       /
 \_____/ -2,-1 \_____/  0,-1 \_____/  2,-1 \_____/
 /     \       /     \       /     \       /     \
/ -3,-1 \_____/ -1,-1 \_____/  1,-1 \_____/  3,-1 \
\       /     \       /     \       /     \       /
 \_____/ -2,0  \_____/  0,0  \_____/  2,0  \_____/
 /     \       /     \       /     \       /     \
/ -3,0  \_____/ -1,0  \_____/  1,0  \_____/  3,0  \
\       /     \       /     \       /     \       /
 \_____/ -2,1  \_____/  0,1  \_____/  2,1  \_____/
 /     \       /     \       /     \       /     \
/ -3,1  \_____/ -1,1  \_____/  1,1  \_____/  3,1  \
\       /     \       /     \       /     \       /
 \_____/       \_____/       \_____/       \_____/

Le pointeur commence à (0, 0).

Les instructions que vous devez prendre en charge sont les suivantes:

  • q: déplacer vers le haut à gauche
  • w: déplacer vers le haut
  • e: déplacer vers le haut à droite
  • a: déplacer vers le bas à gauche
  • s: descendre
  • d: déplacer vers le bas à droite
  • r: faire pivoter la grille dans le sens horaire
  • R: faire pivoter la grille dans le sens antihoraire

Les commandes de rotation font pivoter la grille entière tout en gardant le pointeur aux mêmes coordonnées. (Pourquoi qweasd? Ils correspondent bien aux instructions sur un clavier QWERTY.)

Pour aider à visualiser cela, voici ce que les commandes de mouvement feraient, en supposant que le pointeur commence au milieu:

         _____
        /     \
  _____/   w   \_____
 /     \       /     \
/   q   \_____/   e   \
\       /     \       /
 \_____/       \_____/
 /     \       /     \
/   a   \_____/   d   \
\       /     \       /
 \_____/   s   \_____/
       \       /
        \_____/

Après une rotation dans le sens des aiguilles d'une montre ( r), les commandes sont remappées (imaginez-la comme la rotation de la grille hexagonale entière mais en gardant toujours "w" en place, etc., ce qui équivaut à ce qui suit):

         _____
        /     \
  _____/   e   \_____
 /     \       /     \
/   w   \_____/   d   \
\       /     \       /
 \_____/       \_____/
 /     \       /     \
/   q   \_____/   s   \
\       /     \       /
 \_____/   a   \_____/
       \       /
        \_____/

De même, une rotation dans le sens antihoraire ( R) après cela ramènerait la grille à la normale, et une nouvelle rotation dans le sens antihoraire se "remapperait" qwedsasur aqweds.

L'entrée doit être donnée sous la forme d'une chaîne unique et la sortie peut être soit une chaîne unique jointe par des caractères non numériques (par exemple, 1 2ou 3,4) ou un tableau d'entiers.

Puisqu'il s'agit de , le code le plus court en octets gagnera.

Cas de test:

In                         Out
---------------------------------
edeqaaaswwdqqs             -2, 0
dddddddddd                 10, 5
wswseaeadqdq               0, 0
<empty string>             0, 0
esaaqrweesrqrq             -1, 0
wrwrwrwrw                  -1, 0
RRssrrrs                   -1, -1
aRRRRwddrqrrqqq            -1, -4
rrrrrrrrrrrrRRRRRRrrrrrrq  -1, -1
rrRrRrrRrrrrRRrRrRR        0, 0
Poignée de porte
la source

Réponses:

2

Pyth, 81 octets

J_K1=Y"qwedsa"A,ZZFNz=kxYN ?<kZ=Y?<x\rNZ.>Y1.<Y1A,+G@[JZ1KZJ)k+H@[J_2JK2K)k;,G/H2

La sortie est une liste d'entiers représentant les coordonnées.

Ma solution est vraiment ennuyeuse; il recherche simplement le caractère entré dans un tableau (le qwedsa), puis accède à deux tableaux qui représentent les changements respectifs dans les coordonnées. Par exemple, si l'entrée est w, alors nous obtenons 1 (car c'est le deuxième caractère du tableau). Ensuite, nous ajoutons A[1]à x(où Aest le tableau pour les changements par xrapport aux différentes entrées) et B[1]à y(où Bsont les changements pour y). ret Rsont obtenus en faisant simplement tourner le qwedsaréseau.

Je suis sûr que quelqu'un peut faire beaucoup mieux en utilisant Pyth. Je vais quand même essayer de jouer ma réponse!

Vous pouvez l'essayer ici .

Rhyzomatic
la source
12

Rétine , 353 339 178 175 150 130 129 129 117 octets

R
5$*r
T`aq\we\ds`so`r.+
)`r(.*)
$1
^
:
a
sq
e
wd
+`(.+)q
w$1
+`(.+)d
s$1
+`sw

(.*)(\1w?):
$0$2
+`sw|ws

w+
-$0
\w
1

La sortie est en unaire, séparée par deux points. Cela signifie que vous ne verrez pas vraiment de zéros dans la sortie (bien que la présence de deux points vous dira laquelle des deux coordonnées est nulle, s'il n'y en a qu'une).

Essayez-le en ligne!

C'était vraiment amusant et a fini par être étonnamment court. :)

Explication

Quelques antécédents en premier. Il existe plusieurs systèmes de coordonnées pour décrire les grilles hexagonales. Celui qui a demandé utilise des coordonnées de décalage. C'est essentiellement comme les coordonnées de la grille rectangulaire, sauf qu'un axe "oscille" un peu. En particulier, la question demande la disposition "impaire-q" affichée sur la page liée. Ce système de coordonnées est un peu ennuyeux à utiliser, car la façon dont les coordonnées changent pendant un mouvement dépend non seulement de la direction du mouvement, mais également de la position actuelle.

Un autre système de coordonnées utilise des coordonnées axiales. C'est essentiellement imaginer l'hexgrid comme une tranche diagonale à travers un volume de cubes, et utiliser deux des axes (par exemple x et z) pour trouver une position sur le plan 2D. Sur la grille hexagonale, cela signifie que les deux axes forment un angle de 60 (ou 120) degrés. Ce système est un peu moins intuitif mais beaucoup plus facile à utiliser, car chaque direction correspond à un vecteur "delta" fixe. (Pour une meilleure explication de la façon d'arriver à ce système de coordonnées, consultez le lien et les jolis diagrammes et animations là-bas.)

Alors, voici ce que nous allons faire: nous calculons le mouvement en coordonnées axiales (en prenant soin de la rotation comme suggéré dans le défi, en remappant la signification des commandes), et lorsque nous avons terminé, nous convertissons l'axial en offset impair-q coordonnées.

Les six mouvements correspondent aux vecteurs delta suivants en coordonnées axiales (xz):

q => (-1,  0)
w => ( 0, -1)
e => ( 1, -1)
d => ( 1,  0)
s => ( 0,  1)
a => (-1,  1)

Attendez, c'est Retina, nous devrons travailler avec des nombres unaires. Comment travaillons-nous avec des nombres unaires négatifs? L'idée est d'utiliser deux chiffres différents. L'un représente +1et l'autre représente -1. Cela signifie que, que nous voulions ajouter ou soustraire 1de la position actuelle, nous pouvons toujours le faire en ajoutant un chiffre. Lorsque nous avons terminé, nous réduisons le résultat dans son amplitude (du chiffre correspondant) en annulant les chiffres équilibrés. Ensuite, nous déterminons le signe en fonction du chiffre restant et remplaçons tous les chiffres par 1.

Le plan est de construire les composantes axiales x et z à gauche et à droite de a :(comme séparateur), devant l'entrée. wet ss'ajoutera au côté droit. qet ds'ajoutera au côté gauche, et eet as'ajoutera aux deux côtés. Puisque wet ssont déjà du bon côté de :(qui ira devant), nous les utiliserons respectivement comme les chiffres -1et +1.

Passons en revue le code.

R
5$*r

Nous commençons par transformer chacun Ren cinq rs. Bien sûr, un virage à gauche est le même que cinq virages à droite sur une grille hexadécimale, et ce faisant, nous pouvons faire beaucoup de duplication sur l'étape de remappage.

T`aq\we\ds`so`r.+

Il s'agit d'une étape de translittération qui fait tourner les six commandes, si elles sont trouvées après la première r(traitant ainsi la première r). wet ddoivent être échappés pour les empêcher de se développer dans les classes de caractères. L' oinsère l'ensemble source dans l'ensemble cible, ce qui enregistre un tas d'octets pour ces tâches de rotation. Le mappage de caractères est donc:

aqweds
saqweds

où le dernier sde la deuxième ligne peut simplement être ignoré.

)`r(.*)
$1

Cela supprime le premier rde la chaîne, car il a été traité (j'aurais aimé avoir déjà implémenté des limites de substitution ...). Le )indique également à Retina d'exécuter toutes les étapes jusqu'à celle-ci en boucle jusqu'à ce que la chaîne cesse de changer. Lors des itérations suivantes, la première étape est un no-op car il n'y a plus de Rs et la deuxième étape appliquera une autre rotation tant qu'il restera des rs dans la chaîne.

Lorsque nous avons terminé, nous avons mappé toutes les commandes dans la direction à laquelle elles correspondent sur la grille non tournée et pouvons commencer à les traiter. Bien sûr, ce mouvement n'est qu'une somme de ces vecteurs delta, et les sommes sont commutatives, donc peu importe dans quel ordre nous les traitons maintenant que les rotations ont été éliminées.

^
:

Insérez le délimiteur de coordonnées à l'avant.

Maintenant, nous n'avons pas vraiment besoin de traiter set w. Ils sont nos +1et -1chiffres et ils sont déjà du bon côté du :donc ils vont juste abandonner comme requis à la fin. Nous pouvons faire une autre simplification: aest simplement s + qet eest w + d. Faisons cela:

a
sq
e
wd

Encore une fois, ceux-ci set wabandonneront. Tout ce que nous devons faire est de déplacer ces qs et ds vers l'avant et de les transformer en ws et ss eux-mêmes. Nous le faisons avec deux boucles distinctes:

+`(.+)q
w$1
+`(.+)d
s$1

Alors c'est fait. Temps de conversion des coordonnées axiales en coordonnées décalées. Pour cela, nous devons réduire les chiffres. Cependant, pour l'instant, nous ne nous soucions que du côté gauche. En raison de la façon dont nous avons traité les qs et les ds, nous savons que tous les ss du côté gauche apparaîtront devant tous les ws, nous n'avons donc qu'à vérifier une paire pour les réduire:

+`sw

Maintenant, la conversion réelle. Voici le pseudocode, extrait du lien ci-dessus:

# convert cube to odd-q offset
col = x
row = z + (x - (x&1)) / 2

Droite, donc le côté gauche est déjà correct. Le côté droit a cependant besoin du terme de correction (x - (x&1)) / 2. La prise &1est la même que pour le modulo 2. Elle est essentiellement analysée comme une x/2division entière, arrondie vers moins l'infini. Donc, pour le positif x, nous ajoutons la moitié du nombre de chiffres (arrondi vers le bas), et pour le négatif x, nous soustrayons la moitié du nombre de chiffres (arrondi vers le haut). Cela peut être exprimé de manière étonnamment concise en expression régulière:

(.*)(\1w?):
$0$2

En raison de la gourmandise, même x, le groupe 1 correspondra exactement à la moitié des chiffres, \1l'autre moitié et nous pouvons ignorer le w?. Nous insérons cette moitié après le :(qui est x/2). Si xc'est pair, alors nous devons distinguer le positif du négatif. Si xest positif, alors w?ne correspondra jamais, donc les deux groupes devront toujours correspondre au même nombre de chiffres. Ce n'est pas un problème si le premier sest simplement ignoré, alors nous arrondissons. Si xest négatif et impair, alors la correspondance possible est avec \1(la moitié de l' xarrondi vers le bas) et celle facultative w. Étant donné que les deux vont dans le groupe 2, nous écrirons x/2avec la magnitude arrondie (au besoin).

+`sw|ws

Maintenant, nous réduisons les chiffres sur le côté droit. Cette fois, nous ne connaissons pas l'ordre des set w, nous devons donc tenir compte des deux paires.

w+
-$0

Les deux parties sont maintenant réduites à un seul chiffre répété (ou rien). Si ce chiffre est w, nous insérons un signe moins devant.

\w
1

Et enfin, nous transformons à la fois en wet sen un seul chiffre unaire raisonnable. (Je suppose que je pourrais enregistrer un octet en utilisant wou scomme chiffre unaire, mais cela semble un peu étiré.)

Martin Ender
la source
10
(Suis-je le seul à avoir vu cette réponse apparaître sur la page principale du site et espérait sincèrement qu'elle était écrite en hexagone?)
Addison Crump,
9
@FlagAsSpam Les demandes de cette communauté augmentent sérieusement quand il est possible de décevoir 8 personnes (et en comptant) en résolvant un défi impliquant des entiers signés et des grilles hexagonales avec un langage qui ne peut traiter son entrée que via des expressions régulières. ;)
Martin Ender
1

Python (3,5) 193 185 182 octets

Je calcule également en coordonnées axiales et convertis à la fin.

J'ajoute une optimisation selon la solution @Martin Büttner: je remplace R par r * 5, cela ne change pas le nombre d'octets. Mais avec ce changement, nous pouvons remplacer le deuxième test elif j=='r'par justeelse

La solution suppose que nous ne pouvons pas avoir de caractères invalides dans l'entrée.

def f(i):
 x=y=0;u=-1,0,-1,1,0,1,1,0,1,-1,0,-1;v='dewqas'
 for j in i.replace('R','r'*5):
  w=v.find(j)*2
  if-1<w:x+=u[w];y+=u[w+1]
  else:u=u[2:]+u[:2]
 print(-x,-x-y+(x-(x%2))/2)

Non golfé

def f(i):
  x=y=0
  u=-1,0,-1,1,0,1,1,0,1,-1,0,-1    # operations list xd,yd,xe,ye...
  v='dewqas'                       # letters list in clockwise order 
  i.replace('R','r'*5)             # replace 'R' by 5*'r'
  for j in i:
    w=v.find(j)*2                  # extract letter index
    if-1<w:
      x+=u[w]                      # apply operations
      y+=u[w+1]
    else:
      u=u[2:]+u[:2]                # rotate clockwise the operation string
  print(-x,-x-y+(x-(x%2))/2)       # convert coordinates axial to "odd-q"

Usage

>>> f('wrwrwrwrw')
-1 0.0
>>> f('dddddddddd')
10 5.0
>>> f('edeqaaaswwdqqs')
-2 0.0
Erwan
la source
0

Lot, 708 636 586 569 octets

J'ai utilisé des coordonnées y doublées car cela simplifiait les calculs. Je ne suis pas sûr d'avoir pris en compte la rotation de la manière la plus idéale, mais c'est mieux que de compter le nombre de rs.

Edit: économisé 72 octets en améliorant la gestion de l' Rart. 60 octets enregistrés en optimisant mes set/arelevés. 17 octets enregistrés avec quelques optimisations mineures.

@echo off
set m=%1
set/ay=x=0
set r=r
set g=goto l
:l
set/a"z=y>>1
if "%m%"=="" echo %x% %z%&exit/b
set c=%m:~0,1%
set m=%m:~1%
goto %r:rrrrrr=%%c%
:a
:rq
:rrw
:rrre
:rrrrd
:rrrrrs
set/ax-=2
:w
:re
:rrd
:rrrs
:rrrra
:rrrrrq
set/ax+=1,y-=1
%g%
:q
:rw
:rre
:rrrd
:rrrrs
:rrrrra
set/ay-=2
%g%
:s
:ra
:rrq
:rrrw
:rrrre
:rrrrrd
set/ax-=2
:e
:rd
:rrs
:rrra
:rrrrq
:rrrrrw
set/ax+=+1,y+=1
%g%
:d
:rs
:rra
:rrrq
:rrrrw
:rrrrre
set/ay+=2
%g%
:r
:rr
:rrr
:rrrr
:rrrrr
:rrrrrr
if %c%==R set c=rrrrr
set r=%c%%r%
%g%
Neil
la source
0

05AB1E , 60 octets

.•F?äM•U2Å0IvXy'rQiÀUëy'RQiÁUëykÐ5α‚ßsD3%_s3›·+‚<+]Ć`DÉ-2÷+‚

Essayez-le en ligne ou vérifiez tous les cas de test .

Explication:

Explication générale:

Nous commençons par une chaîne "qwedsa"et une coordonnée [0,0], et bouclons sur les caractères de l'entrée.
S'il s'agit d'un "r" ou d'un "R", nous faisons tourner cette chaîne respectivement vers la gauche ou la droite.
Sinon, nous obtenons l'index basé sur 0 dans cette chaîne et le mappons comme suit:

q → 0 → [-1,  0]
w → 1 → [ 0, -1]
e → 2 → [ 1, -1]
d → 3 → [ 1,  0]
s → 4 → [ 0,  1]
a → 5 → [-1,  1]

Xy

 x   indices     y   indices
-1 ← 0;5        -1 ← 1;2
 0 ← 1;4         0 ← 0;3
 1 ← 2;3         1 ← 4;5

k

X=mjen(k,unebs(k-5))-1
y=(0k(mod3))+2(k>3)-1

yXX

y=y+X-X(mod2)2

Explication du code:

.•FM         # Push compressed string "qwedsa"
       U        # Pop and store it in variable `X`
2Å0             # Push list [0,0]
                # (many 3-byte alternatives for this: `00S`; `т¦S`; `0D‚`; `1¾‰`; etc.)
   Iv           # Loop over each character `y` of the input:
     X          #  Push string `X`
      y'rQi    '#  If `y` equals "r":
           À    #   Rotate string `X` once towards the left
            U   #   And pop and store it as new value for `X`
      ëy'RQi   '#  Else-if `y` equals "R":
            ÁU  #   Do the same, but rotate right instead
      ë         #  Else:
       yk       #   Get the 0-based index of `y` in the string `X`
         Ð      #   Triplicate this index
          5α    #   Take the absolute difference with 5
            ‚ß  #   Pair it with the original index, and pop and push the minimum
                #   (maps 0→[0,5]→0; 1→[1,4]→1; 2→[2,3]→2;
                #         3→[3,2]→2; 4→[4,1]→1; 5→[5,0]→0)
         sD     #   Swap to get the original index again, and duplicate it
           3%   #   Take modulo 3
             _  #   And check if it's equals to 0 (1 if truthy; 0 if falsey)
          s3   #   Swap to take the index again, and check if it's larger than 
                #   (again, 1 if truthy; 0 if falsey)
             ·  #   Double this
          +     #   And add both checks together
                #   (maps 0→1+0→1; 1→0+0→0; 2→0+0→0;
                #         3→1+0→1; 4→0+2→2; 5→0+2→2)
               #   Pair both mapped values together
          <     #   Decrease both by 1, so it becomes: 0→-1; 1→0; 2→1
           +    #   And add it to the current coordinates
    ]           # After the loop with inner if-else statements:
     Ć          # Enclose the coordinate, appending its own head: [x,y] becomes [x,y,x]
      `         # Push all three values separated to the stack
       D        # Duplicate this x
        É       # Check if its odd (1 if truthy; 0 if falsey)
         -      # Subtract it from the duplicated x
          2÷    # Integer-divide it by 2
            +   # Add it to y
               # And pair it with the original x again
                # (after which the result is output implicitly)

Voir cette astuce 05AB1E (section Comment compresser des chaînes ne faisant pas partie du dictionnaire? ) Pour comprendre pourquoi.•F?äM• est "qwedsa".

Kevin Cruijssen
la source
-1

Python 3, 227 octets

def G(s):
 q='qwedsa'
 d=[-1,0,1,1,0,-1,-1,-2,-1,1,2,1]
 X=Y=0
 for c in s:
  if c in q:
   n = q.find(c)
   X += d[n]
   Y += d[n+6]
  if c == 'r':
   q = q[1:]+q[0]
  if c == 'R':
   q = q[5]+q[0:5]
 print(X, int((Y-X%2)/2))
Austin Hastings
la source
J'utilise Python 3.5.0b3sur MacOS, et même si j'ai eu une erreur dans 5 et 6, en raison de l'arrondissement, le reste était correct. (Depuis fixe via Edit). Quelle version de Python utilisez-vous?
Austin Hastings
1
@AustinHastings Je suis sur Python 3 sur Debian unstable.
Poignée de porte