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
A saída é unária, separada por dois pontos. Isso significa que você realmente não verá zeros na saída (embora a presença de dois pontos indique qual das duas coordenadas é zero, se houver apenas uma).
Experimente online!
Isso foi muito divertido e acabou sendo surpreendentemente curto. :)
Explicação
Alguns antecedentes primeiro. Existem vários sistemas de coordenadas para descrever grades hexagonais. A pessoa solicitada usa coordenadas de deslocamento. Isso é essencialmente como coordenadas retangulares da grade, exceto que um eixo "oscila" um pouco. Em particular, a pergunta solicita o layout "ímpar-q" mostrado na página vinculada. Esse sistema de coordenadas é um pouco chato de se trabalhar, porque o modo como as coordenadas mudam durante um movimento depende não apenas da direção do movimento, mas também da posição atual.
Outro sistema de coordenadas usa coordenadas axiais. Isso é essencialmente imaginar a hexgrid como uma fatia diagonal através de um volume de cubos e usar dois dos eixos (por exemplo, x e z) para encontrar uma posição no plano 2D. Na grade hexagonal, isso significa que os dois eixos formam um ângulo de 60 (ou 120) graus. Esse sistema é um pouco menos intuitivo, mas muito mais fácil de trabalhar, pois todas as direções correspondem a um vetor "delta" fixo. (Para uma melhor explicação de como chegar a esse sistema de coordenadas, confira o link e os adoráveis diagramas e animações.)
Então, aqui está o que faremos: calculamos o movimento em coordenadas axiais (cuidando da rotação como sugerido no desafio, remapeando o significado dos comandos) e, quando terminamos, convertemos axial em offset-q impar coordenadas.
Os seis movimentos são mapeados para os seguintes vetores delta em coordenadas axiais (xz):
q => (-1, 0)
w => ( 0, -1)
e => ( 1, -1)
d => ( 1, 0)
s => ( 0, 1)
a => (-1, 1)
Espera, aqui é Retina, teremos que trabalhar com números unários. Como trabalhamos com números unários negativos? A idéia é usar dois dígitos diferentes. Um representa +1e o outro representa -1. Isso significa que, independentemente de querermos adicionar ou subtrair 1da posição atual, sempre podemos fazer isso adicionando um dígito. Quando terminamos, reduzimos o resultado em sua magnitude (do dígito correspondente) cancelando dígitos balanceados. Depois descobrimos o sinal com base no dígito restante e substituímos todos os dígitos por 1.
O plano é construir os componentes axiais x e z à esquerda e à direita de a :(como um separador), na frente da entrada. we sserá adicionado ao lado direito. qe dserá adicionado ao lado esquerdo ee aserá adicionado aos dois lados. Como we sjá estamos no lado correto do :(que irá na frente), os usaremos como os dígitos -1e +1, respectivamente.
Vamos analisar o código.
R
5$*r
Começamos transformando cada um Rem cinco rsegundos. Obviamente, uma curva à esquerda é igual a cinco curvas à direita em uma grade hexadecimal e, ao fazer isso, podemos duplicar bastante na etapa de remapeamento.
T`aq\we\ds`so`r.+
Este é um estágio de transliteração que gira os seis comandos, se forem encontrados após o primeiro r(processando assim o primeiro r). we dprecisa ser escapado para impedir que eles se expandam para as classes de personagens. Ele oinsere o conjunto de origem no conjunto de destino, o que economiza um monte de bytes para essas tarefas de rotação. O mapeamento de caracteres é, portanto:
aqweds
saqweds
onde o último sna segunda linha pode ser simplesmente ignorado.
)`r(.*)
$1
Isso remove o primeiro rda string, porque foi processado (eu gostaria de já ter implementado limites de substituição ...). O )comando também diz ao Retina para executar todos os estágios até este em um loop até que a string pare de mudar. Nas iterações subseqüentes, o primeiro estágio é um no-op porque não há mais se Ro segundo estágio aplicará outra rotação enquanto houver rs restantes na string.
Quando terminamos, mapeamos todos os comandos na direção a que correspondem na grade não rotacionada e podemos começar a processá-los. É claro que esse movimento é apenas uma soma desses vetores delta e as somas são comutativas, portanto, não importa realmente em que ordem os processamos agora que as rotações foram eliminadas.
^
:
Insira o delimitador de coordenadas na frente.
Agora realmente não precisamos processar se w. Eles são nossos +1e -1dígitos e já estão no lado correto da tela, :para que acabem desistindo conforme necessário no final. Podemos fazer outra simplificação: aé simples s + qe eé w + d. Vamos fazer isso:
a
sq
e
wd
Mais uma vez, aqueles se wsimplesmente desistirão. Tudo o que precisa fazer é mover essas qs e ds para a frente e transformá-los em ws e ss eles mesmos. Fazemos isso com dois loops separados:
+`(.+)q
w$1
+`(.+)d
s$1
Então está feito. Hora da conversão de coordenadas axiais para deslocadas. Para isso, precisamos recolher os dígitos. No entanto, por enquanto, nos preocupamos apenas com o lado esquerdo. Devido à forma como temos processados os qs e ds, sabemos que todas as ss em lado esquerdo vai aparecer na frente de quaisquer ws, por isso, só precisa verificar um par para o colapso do-los:
+`sw
Agora a conversão real. Aqui está o pseudocódigo, retirado do link acima:
# convert cube to odd-q offset
col = x
row = z + (x - (x&1)) / 2
Certo, então o lado esquerdo já está correto. O lado direito precisa do termo de correção (x - (x&1)) / 2. Tomar &1é o mesmo que o módulo 2. Isso basicamente analisa como x/2, divisão inteira, arredondada para menos infinito. Portanto, para positivo x, adicionamos metade do número de dígitos (arredondado para baixo) e, para negativo x, subtraímos metade do número de dígitos (arredondado para cima). Isso pode ser expresso surpreendentemente concisa na regex:
(.*)(\1w?):
$0$2
Devido à ganância, para o par x, o grupo 1 corresponderá exatamente a metade dos dígitos, \1a outra metade e podemos ignorar o w?. Nós inserimos essa metade após o :(que é x/2). Se xfor par, precisamos distinguir positivo e negativo. Se xfor positivo, w?nunca corresponderá, portanto os dois grupos ainda terão que corresponder ao mesmo número de dígitos. Não há problema se o primeiro sfor simplesmente pulado, então arredondamos para baixo. Se xfor negativo e ímpar, a possível correspondência será com \1(metade do xarredondado para baixo) e opcional w. Como os dois entram em grupo 2, escreveremos x/2com a magnitude arredondada para cima (conforme necessário).
+`sw|ws
Agora, reduzimos os dígitos no lado direito. Desta vez, não sabemos a ordem do se w, portanto, precisamos considerar os dois pares.
w+
-$0
Agora, ambas as partes são reduzidas a um único dígito repetido (ou nada). Se esse dígito for w, inserimos um sinal de menos na frente.
\w
1
E, finalmente, transformar tanto em we spara um único dígito unário razoável. (Suponho que eu poderia salvar um byte usando wou scomo o dígito unário, mas isso parece um pouco exagerado.)