Movimiento en una cuadrícula hexagonal

15

Dada una entrada de una serie de caracteres que representan movimientos en una cuadrícula hexagonal, genera las coordenadas finales del "puntero".

Nuestros hexágonos se numerarán así (imagine una cuadrícula rectangular con cada columna impar desplazada ligeramente hacia abajo):

  _____         _____         _____         _____
 /     \       /     \       /     \       /     \
/ -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  \
\       /     \       /     \       /     \       /
 \_____/       \_____/       \_____/       \_____/

El puntero comienza en (0, 0).

Las instrucciones que debe apoyar son las siguientes:

  • q: mover hacia arriba-izquierda
  • w: ascender
  • e: mover hacia arriba a la derecha
  • a: mover hacia abajo-izquierda
  • s: mover hacia abajo
  • d: mover hacia abajo a la derecha
  • r: rotar la cuadrícula en sentido horario
  • R: rotar la cuadrícula en sentido antihorario

Los comandos de rotación rotan toda la cuadrícula mientras se mantiene el puntero en las mismas coordenadas. (¿Por qué qweasd? Coinciden con las instrucciones muy bien en un teclado QWERTY).

Para ayudar a visualizar esto, esto es lo que harían los comandos de movimiento, suponiendo que el puntero comience en el medio:

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

Después de una rotación en el sentido de las agujas del reloj ( r), los comandos se reasignan a (imagínelo girando toda la cuadrícula hexadecimal pero manteniendo "w" hacia arriba, etc., que es equivalente a lo siguiente):

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

Del mismo modo, en sentido antihorario (rotación R), después de que volvería la rejilla a la normalidad, y la rotación en sentido antihorario de nuevo haría "remap" qwedsaa aqweds.

La entrada debe darse como una sola cadena, y la salida puede ser una sola cadena unida por cualquier carácter no numérico (ej. 1 2O 3,4) o una matriz de enteros.

Como se trata de , el código más corto en bytes ganará.

Casos de prueba:

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
Pomo de la puerta
fuente

Respuestas:

2

Pyth, 81 bytes

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

La salida es una lista de enteros que representan las coordenadas.

Mi solución es realmente muy aburrida; solo busca el carácter ingresado en una matriz (the qwedsa) y luego accede a dos matrices que representan los cambios respectivos en las coordenadas. Por ejemplo, si la entrada es w, entonces obtenemos 1 (ya que es el segundo carácter de la matriz). Luego agregamos A[1]a x(dónde Aestá la matriz de los cambios con xrespecto a las diferentes entradas) y B[1]a y(dónde Bestán los cambios y). ry Rse logran simplemente girando la qwedsamatriz.

Estoy seguro de que alguien puede hacerlo mucho mejor usando Pyth. ¡Sin embargo, continuaré tratando de jugar mi respuesta!

Puedes probarlo aquí .

Rhyzomatic
fuente
12

Retina , 353 339 178 175 150 130 129 117 bytes

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 salida está en unario, separada por dos puntos. Eso significa que realmente no verá ceros en la salida (aunque la presencia de dos puntos le indicará cuál de las dos coordenadas es cero, si solo hay una).

Pruébalo en línea!

Esto fue muy divertido y terminó siendo sorprendentemente corto. :)

Explicación

Algunos antecedentes primero. Existen varios sistemas de coordenadas para describir las cuadrículas hexagonales. El que pidió utiliza coordenadas de desplazamiento. Eso es esencialmente como coordenadas de cuadrícula rectangular, excepto que un eje "se tambalea" un poco. En particular, la pregunta solicita el diseño "impar q" que se muestra en la página vinculada. Es un poco molesto trabajar con este sistema de coordenadas, porque la forma en que cambian las coordenadas durante un movimiento depende no solo de la dirección del movimiento, sino también de la posición actual.

Otro sistema de coordenadas utiliza coordenadas axiales. Eso es esencialmente imaginar la cuadrícula hexagonal como un corte diagonal a través de un volumen de cubos, y usar dos de los ejes (por ejemplo, x y z) para encontrar una posición en el plano 2D. En la cuadrícula hexadecimal, eso significa que los dos ejes forman un ángulo de 60 (o 120) grados. Este sistema es un poco menos intuitivo pero mucho más fácil de trabajar, ya que cada dirección corresponde a un vector "delta" fijo. (Para una mejor explicación de cómo llegar a este sistema de coordenadas, consulte el enlace y los encantadores diagramas y animaciones allí).

Entonces, esto es lo que haremos: calculamos el movimiento en coordenadas axiales (cuidando la rotación como se sugiere en el desafío, reasignando el significado de los comandos), y cuando terminamos, convertimos axial a offset impar-q coordenadas

Los seis movimientos se asignan a los siguientes vectores delta en coordenadas axiales (xz):

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

Espera, esta es Retina, tendremos que trabajar con números unarios. ¿Cómo trabajamos con números unarios negativos? La idea es usar dos dígitos diferentes. Uno representa +1y el otro representa -1. Eso significa que independientemente de si queremos sumar o restar 1de la posición actual, siempre podemos hacerlo agregando un dígito. Cuando terminamos, colapsamos el resultado en su magnitud (del dígito correspondiente) cancelando dígitos balanceados. Luego calculamos el signo en función del dígito restante y reemplazamos todos los dígitos con 1.

El plan es construir los componentes axiales x y z a la izquierda y derecha de a :(como separador), frente a la entrada. wy sse agregará al lado derecho. qy dse agregará al lado izquierdo, ey ase agregará a ambos lados. Como wya sestamos en el lado correcto de :(que irá al frente), los utilizaremos como dígitos -1y +1, respectivamente.

Veamos el código.

R
5$*r

Comenzamos convirtiendo cada uno Ren cinco rs. Por supuesto, un giro a la izquierda es lo mismo que cinco giros a la derecha en una cuadrícula hexagonal, y al hacerlo podemos duplicar mucho el paso de reasignación.

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

Esta es una etapa de transliteración que rota los seis comandos, si se encuentran después del primero r(procesando así el primero r). wy dnecesitan escapar para evitar que se expandan a clases de personajes. El oinserta el conjunto de origen en el conjunto de objetivos que ahorra un montón de bytes para estas tareas de rotación. El mapeo de caracteres es por lo tanto:

aqweds
saqweds

donde el último sen la segunda fila simplemente puede ignorarse.

)`r(.*)
$1

Esto elimina el primero rde la cadena, porque se ha procesado (desearía haber implementado límites de sustitución ...). El )también dice Retina para ejecutar todas las etapas hasta éste en un bucle hasta que la cuerda deja de cambiar. En las iteraciones posteriores, la primera etapa es un no-op porque no hay más Rsy la segunda etapa aplicará otra rotación siempre que queden rs en la cadena.

Cuando hayamos terminado, hemos asignado todos los comandos a la dirección que corresponden en la cuadrícula no rotada y podemos comenzar a procesarlos. Por supuesto, este movimiento es solo una suma de esos vectores delta, y las sumas son conmutativas, por lo que realmente no importa en qué orden las procesemos ahora que se han eliminado las rotaciones.

^
:

Inserte el delimitador de coordenadas en el frente.

Ahora realmente no necesitamos procesar sy w. Son nuestros +1y -1dígitos y ya están en el lado correcto del, :por lo que simplemente se abandonarán como se requiere al final. Podemos hacer otra simplificación: aes simple s + qy ees w + d. Vamos a hacer eso:

a
sq
e
wd

Una vez más, esos sy wsimplemente abandonarán. Todo lo que tenemos que hacer es mover esos qs y ds en la parte delantera y los convierten en ws y ssí lo es. Hacemos eso con dos bucles separados:

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

Así que ya está hecho. Tiempo para la conversión de coordenadas axiales a offset. Para eso necesitamos colapsar los dígitos. Sin embargo, por ahora solo nos importa el lado izquierdo. Debido a la forma en que hemos procesado los qsys d, sabemos que todos los ss en el lado izquierdo aparecerán frente a cualquier ws, por lo que solo necesitamos verificar un par para colapsarlos:

+`sw

Ahora la conversión real. Aquí está el pseudocódigo, tomado del enlace de arriba:

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

Derecha, entonces el lado izquierdo ya está correcto. Sin (x - (x&1)) / 2embargo, el lado derecho necesita el término de corrección . Tomar &1es lo mismo que el módulo 2. Esto básicamente se analiza como x/2, división entera, redondeada hacia menos infinito. Entonces, para positivo x, sumamos la mitad del número de dígitos (redondeado hacia abajo), y para negativo x, restamos la mitad del número de dígitos (redondeado hacia arriba). Esto se puede expresar de manera sorprendentemente concisa en expresiones regulares:

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

Debido a la codicia, incluso x, el grupo 1 coincidirá exactamente con la mitad de los dígitos, \1la otra mitad y podemos ignorar el w?. Insertamos esa mitad después de :(que es x/2). Si xes par, entonces necesitamos distinguir entre positivo y negativo. Si xes positivo, entonces w?nunca coincidirá, por lo que los dos grupos aún tendrán que coincidir con el mismo número de dígitos. Eso no es problema si el primero ssimplemente se omite, por lo que redondeamos hacia abajo. Si xes negativo e impar, entonces la posible coincidencia es con \1(la mitad de xredondeado hacia abajo) y eso es opcional w. Dado que ambos van en grupo 2, escribiremos x/2con la magnitud redondeada (según sea necesario).

+`sw|ws

Ahora colapsamos los dígitos en el lado derecho. Esta vez, no sabemos el orden de los sy w, por lo que debemos tener en cuenta ambos pares.

w+
-$0

Ambas partes ahora se reducen a un solo dígito repetido (o nada). Si ese dígito es w, insertamos un signo menos al frente.

\w
1

Y, finalmente, nos volvemos a ambos en wy sen un solo dígito unario razonable. (Supongo que podría guardar un byte usando wo scomo dígito unario, pero eso parece un poco exagerado).

Martin Ender
fuente
10
(¿Soy el único que vio esta respuesta venga arriba en la página principal del sitio y muy caro esperaba que fuera escrito en Hexagony?)
Addison Crump
99
@FlagAsSpam Las demandas de esta comunidad aumentan seriamente cuando es posible decepcionar a 8 personas (y contar) resolviendo un desafío que involucra enteros firmados y cuadrículas hexagonales con un lenguaje que solo puede procesar su entrada a través de expresiones regulares. ;)
Martin Ender
1

Python (3,5) 193 185 182 bytes

También calculo en coordenadas axiales y convierto al final.

Agrego algo de optimización de acuerdo con la solución @Martin Büttner: reemplazo R por r * 5, no cambia el recuento de bytes. Pero con este cambio podemos reemplazar la segunda prueba elif j=='r'con soloelse

La solución supone que no podemos tener caracteres no válidos en la entrada.

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)

Sin 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"

Uso

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

Lote, 708 636 586 569 bytes

Usé coordenadas y duplicadas porque simplificaba las matemáticas. No estoy seguro de haber tenido en cuenta la rotación de la manera más ideal, pero es mejor contar el número de rs.

Editar: ahorró 72 bytes al mejorar el manejo de Rs. Ahorré 60 bytes al optimizar mis set/adeclaraciones. Guardado 17 bytes con algunas optimizaciones menores.

@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
fuente
0

05AB1E , 60 bytes

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

Pruébelo en línea o verifique todos los casos de prueba .

Explicación:

Explicación general:

Comenzamos con una cadena "qwedsa"y una coordenada [0,0], y recorremos los caracteres de la entrada.
Si es una "r" o "R", rotamos esta cadena hacia la izquierda o la derecha, respectivamente.
Si no, obtenemos el índice basado en 0 en esta cadena y lo asignamos de la siguiente manera:

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=metroyonorte(k,unsis(k-5 5))-1
y=(0 0k(modificación3))+2(k>3)-1

yXX

y=y+X-X(modificación2)2

Explicación del código:

.•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)

Ver este consejo 05AB1E mío (sección Cómo comprimir cadenas que no forman parte del diccionario? ) Para entender por qué .•F?äM•es "qwedsa".

Kevin Cruijssen
fuente
-1

Python 3, 227 bytes

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
fuente
Estoy usando Python 3.5.0b3MacOS, y aunque recibí un error en 5 y 6, debido al redondeo, el resto fue correcto. (Desde arreglado a través de Editar). ¿Qué versión de Python estás usando?
Austin Hastings
1
@AustinHastings Estoy en Python 3 en Debian inestable.
Pomo de la puerta