Retina , 353 339 178 175 150 130 129 117 byte
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
L'output è in unario, separato da due punti. Ciò significa che non vedrai davvero zero nell'output (anche se la presenza di due punti ti dirà quale delle due coordinate è zero, se ce n'è solo una).
Provalo online!
Questo è stato davvero divertente e alla fine è stato sorprendentemente breve. :)
Spiegazione
Prima alcuni retroscena. Esistono diversi sistemi di coordinate per descrivere le griglie esagonali. Quello richiesto usa le coordinate offset. È essenzialmente come le coordinate della griglia rettangolare, tranne per il fatto che un asse "oscilla" un po '. In particolare, la domanda richiede il layout "dispari-q" mostrato nella pagina collegata. Questo sistema di coordinate è un po 'noioso con cui lavorare, perché il modo in cui le coordinate cambiano durante uno spostamento dipende non solo dalla direzione dello spostamento ma anche dalla posizione corrente.
Un altro sistema di coordinate utilizza coordinate assiali. Questo essenzialmente immagina l'esgriglia come una fetta diagonale attraverso un volume di cubi e usa due degli assi (es. Xe z) per trovare una posizione sul piano 2D. Sulla griglia esadecimale, ciò significa che i due assi formano un angolo di 60 (o 120) gradi. Questo sistema è un po 'meno intuitivo ma molto più facile da lavorare, poiché ogni direzione corrisponde a un vettore "delta" fisso. (Per una migliore spiegazione di come arrivare a questo sistema di coordinate, controlla il link e gli splendidi diagrammi e animazioni lì.)
Quindi, ecco cosa faremo: calcoliamo il movimento in coordinate assiali (prendendoci cura della rotazione come suggerito nella sfida, rimappando il significato dei comandi), e quando abbiamo finito convertiamo assiale in offset dispari-q coordinate.
Le sei mosse si mappano ai seguenti vettori delta in coordinate assiali (xz):
q => (-1, 0)
w => ( 0, -1)
e => ( 1, -1)
d => ( 1, 0)
s => ( 0, 1)
a => (-1, 1)
Aspetta, questa è Retina, dovremo lavorare con numeri unari. Come lavoriamo con numeri unari negativi? L'idea è di usare due cifre diverse. Uno rappresenta+1
e l'altro rappresenta -1
. Ciò significa che indipendentemente dal fatto che vogliamo aggiungere o sottrarre 1
dalla posizione corrente, possiamo sempre farlo aggiungendo una cifra. Quando abbiamo finito comprimiamo il risultato nella sua grandezza (della cifra corrispondente) cancellando le cifre bilanciate. Quindi calcoliamo il segno in base alla cifra rimanente e sostituiamo tutte le cifre con 1
.
Il piano è costruire i componenti assiali x e z a sinistra e a destra di un :
(come separatore), davanti all'ingresso. w
e s
si aggiungerà al lato destro. q
e d
verrà aggiunto sul lato sinistro e
e a
verrà aggiunto su entrambi i lati. Da w
es
sono già sul lato corretto del :
(che andrà in primo piano), useremo quelli come i numeri -1
e +1
, rispettivamente.
Analizziamo il codice.
R
5$*r
Iniziamo trasformando ciascuno R
in cinquer
secondi. Naturalmente, una svolta a sinistra è la stessa di cinque svolte a destra su una griglia esadecimale, e così facendo possiamo fare molte duplicazioni sul passaggio di rimappatura.
T`aq\we\ds`so`r.+
Questa è una fase di traslitterazione che ruota i sei comandi, se vengono trovati dopo il primo r
(elaborando così il primo r
). w
e d
devono essere evitati per impedire che si espandano in classi di caratteri. Ilo
inserisce il set sorgente nel set di destinazione che salva un mazzo di byte per queste operazioni di rotazione. La mappatura dei caratteri è quindi:
aqweds
saqweds
dove l'ultimo s
nella seconda riga può essere semplicemente ignorato.
)`r(.*)
$1
Questo rimuove il primo r
dalla stringa, perché è stato elaborato (vorrei aver già implementato i limiti di sostituzione ...). Il)
dice anche Retina per eseguire tutte le fasi fino a questo in un ciclo fino a quando la stringa smette di cambiare. Nelle iterazioni successive, il primo stadio è no-op perché non ci sono più se R
il secondo stadio applica un'altra rotazione fintanto che ci sono r
s nella stringa.
Al termine, abbiamo mappato tutti i comandi nella direzione in cui corrispondono sulla griglia non ruotata e possiamo iniziare a elaborarli. Naturalmente questo movimento è solo una somma di quei vettori delta e le somme sono commutative, quindi non importa in quale ordine le elaboriamo ora che le rotazioni sono state eliminate.
^
:
Inserire il delimitatore di coordinate nella parte anteriore.
Ora non abbiamo davvero bisogno di elaborare s
e w
. Sono nostre +1
e -1
cifre e sono già dalla parte corretta del, :
quindi lasceranno cadere come richiesto alla fine. Possiamo fare un'altra semplificazione: a
è semplicemente s + q
ed e
è w + d
. Facciamolo:
a
sq
e
wd
Ancora una volta, quelli s
e w
cadranno. Tutto quello che dobbiamo fare è spostare quei q
s e d
s per la parte anteriore e li trasformano in w
s e s
si s. Lo facciamo con due loop separati:
+`(.+)q
w$1
+`(.+)d
s$1
Quindi è fatto. Tempo per la conversione da coordinate assiali a coordinate offset. Per questo dobbiamo comprimere le cifre. Tuttavia, per ora ci preoccupiamo solo del lato sinistro. A causa del modo in cui abbiamo elaborato le q
s e le d
s, sappiamo che tutte le s
s nella parte sinistra appariranno davanti a tutte le w
s, quindi dobbiamo solo controllare una coppia per farle crollare:
+`sw
Ora la conversione effettiva. Ecco lo pseudocodice, preso dal link sopra:
# convert cube to odd-q offset
col = x
row = z + (x - (x&1)) / 2
Destra, quindi il lato sinistro è già corretto. Tuttavia, il lato destro richiede il termine di correzione (x - (x&1)) / 2
. Prendendo &1
è lo stesso del modulo 2. Questo in sostanza analizza come x/2
, divisione intera, arrotondata verso meno infinito. Quindi, per positivo x
, aggiungiamo la metà del numero di cifre (arrotondato per difetto) e per negativo x
, sottraggiamo la metà del numero di cifre (arrotondato per eccesso). Questo può essere espresso in modo sorprendentemente conciso in regex:
(.*)(\1w?):
$0$2
A causa dell'avidità, anche il x
gruppo 1 corrisponderà esattamente alla metà delle cifre, \1
l'altra metà e possiamo ignorare il w?
. Inseriamo quella metà dopo il :
(che è x/2
). Se x
è pari, allora dobbiamo distinguere il positivo e il negativo. Se x
è positivo, w?
non corrisponderà mai, quindi i due gruppi dovranno comunque corrispondere allo stesso numero di cifre. Non è un problema se il primo s
viene semplicemente ignorato, quindi arrotondiamo per difetto. Se x
è negativo e dispari, la corrispondenza possibile è con \1
(metà x
arrotondata per difetto) e quella facoltativa w
. Dato che entrambi vanno in gruppo 2
, scriveremo x/2
con la grandezza arrotondata per eccesso (come richiesto).
+`sw|ws
Ora comprimiamo le cifre sul lato destro. Questa volta, non conosciamo l'ordine di s
e w
, quindi dobbiamo tenere conto di entrambe le coppie.
w+
-$0
Entrambe le parti sono ora ridotte a una singola cifra ripetuta (o nulla). Se quella cifra è w
, inseriamo un segno meno davanti.
\w
1
E infine trasformiamo sia in w
che s
in un'unica cifra unaria ragionevole. (Suppongo di poter salvare un byte usando w
o s
come cifra unaria, ma sembra un po 'allungato.)