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
Die Ausgabe erfolgt unär, getrennt durch einen Doppelpunkt. Das bedeutet, dass Sie in der Ausgabe keine wirklichen Nullen sehen (obwohl das Vorhandensein eines Doppelpunkts anzeigt, welche der beiden Koordinaten Null ist, wenn es nur eine gibt).
Probieren Sie es online!
Das hat wirklich Spaß gemacht und war überraschend kurz. :)
Erläuterung
Einige Hintergrundinformationen zuerst. Es gibt mehrere Koordinatensysteme, um hexagonale Gitter zu beschreiben. Die angeforderte verwendet Offset-Koordinaten. Das entspricht im Wesentlichen rechteckigen Gitterkoordinaten, mit der Ausnahme, dass eine Achse ein wenig "wackelt". In der Frage wird insbesondere das auf der verlinkten Seite angezeigte "ungerade-q" -Layout abgefragt. Die Arbeit mit diesem Koordinatensystem ist etwas ärgerlich, da die Änderung der Koordinaten während einer Bewegung nicht nur von der Bewegungsrichtung, sondern auch von der aktuellen Position abhängt.
Ein anderes Koordinatensystem verwendet axiale Koordinaten. Das heißt, Sie stellen sich das Hex-Gitter als eine diagonale Scheibe durch ein Volumen von Würfeln vor und verwenden zwei der Achsen (z. B. x und z), um eine Position auf der 2D-Ebene zu finden. Auf dem Sechskantgitter bedeutet dies, dass die beiden Achsen einen Winkel von 60 (oder 120) Grad bilden. Dieses System ist etwas weniger intuitiv, aber viel einfacher zu handhaben, da jede Richtung einem festen "Delta" -Vektor entspricht. (Für eine bessere Erklärung, wie Sie zu diesem Koordinatensystem gelangen, sehen Sie sich den Link und die schönen Diagramme und Animationen an.)
Wir berechnen die Bewegung in Axialkoordinaten (wobei die Rotation berücksichtigt wird, wie in der Aufforderung angegeben, indem die Bedeutung der Befehle neu zugeordnet wird). Anschließend konvertieren wir die axiale in die ungerade-q-Verschiebung Koordinaten.
Die sechs Bewegungen werden in (xz) Achsenkoordinaten auf die folgenden Delta-Vektoren abgebildet:
q => (-1, 0)
w => ( 0, -1)
e => ( 1, -1)
d => ( 1, 0)
s => ( 0, 1)
a => (-1, 1)
Warten Sie, das ist Retina, wir müssen mit unären Zahlen arbeiten. Wie arbeiten wir mit negativen Unärzahlen? Die Idee ist, zwei verschiedene Ziffern zu verwenden. Einer repräsentiert +1
und der andere repräsentiert -1
. Das heißt, unabhängig davon, ob wir 1
von der aktuellen Position addieren oder subtrahieren möchten , können wir dies immer durch Hinzufügen einer Ziffer tun. Wenn wir fertig sind, reduzieren wir das Ergebnis auf seine Größe (der entsprechenden Ziffer), indem wir ausgeglichene Ziffern löschen. Dann ermitteln wir das Vorzeichen anhand der verbleibenden Ziffer und ersetzen alle Ziffern durch 1
.
Es ist geplant, die axialen x- und z-Komponenten links und rechts von a :
(als Trennzeichen) vor dem Eingang aufzubauen . w
und s
wird auf der rechten Seite hinzugefügt. q
und d
werden auf der linken Seite hinzugefügt , und e
und a
werden auf beiden Seiten hinzugefügt. Da w
und s
bereits auf der richtigen Seite von :
(die voran gehen wird), werden wir diese als -1
und +1
Ziffern verwenden.
Lass uns den Code durchgehen.
R
5$*r
Wir fangen damit an, dass wir jeweils R
fünf r
s machen. Natürlich entspricht eine Linkskurve fünf Rechtskurven in einem Hex-Gitter. Auf diese Weise können wir den Remapping-Schritt erheblich duplizieren.
T`aq\we\ds`so`r.+
Dies ist eine Transliterationsstufe, bei der die sechs Befehle rotiert werden, wenn sie nach dem ersten gefunden werden r
(wodurch der erste verarbeitet wird r
). w
und d
müssen entkommen werden, um zu verhindern, dass sie in Charakterklassen expandieren. Der o
fügt den Quellensatz in den Zielsatz ein, wodurch eine Reihe von Bytes für diese Rotationsaufgaben gespeichert werden. Die Zeichenzuordnung lautet daher:
aqweds
saqweds
wo der letzte s
in der zweiten Reihe einfach ignoriert werden kann.
)`r(.*)
$1
Dadurch wird die erste r
Zeichenfolge aus der Zeichenfolge entfernt, da sie verarbeitet wurde (ich wünschte, ich hätte bereits Substitutionsbeschränkungen implementiert ...). Das )
sagt Retina auch, dass sie alle Stufen bis zu dieser in einer Schleife durchlaufen soll, bis sich die Saite nicht mehr ändert. Bei nachfolgenden Iterationen ist die erste Stufe ein No-Op, da keine weiteren R
s vorhanden sind und die zweite Stufe eine weitere Drehung anwendet, solange noch r
s in der Zeichenfolge vorhanden sind.
Wenn wir fertig sind, haben wir alle Befehle der Richtung zugeordnet, der sie auf dem nicht gedrehten Raster entsprechen, und können mit der Verarbeitung dieser Befehle beginnen. Natürlich ist diese Bewegung nur eine Summe dieser Delta-Vektoren, und die Summen sind kommutativ, so dass es nicht wirklich wichtig ist, in welcher Reihenfolge wir sie jetzt verarbeiten, da die Rotationen eliminiert wurden.
^
:
Fügen Sie den Koordinatenbegrenzer vorne ein.
Jetzt brauchen wir nicht wirklich zu verarbeiten s
und w
. Sie sind unsere +1
und die -1
Ziffern und befinden sich bereits auf der richtigen Seite, :
sodass sie am Ende nur wie erforderlich aussteigen. Wir können eine weitere Vereinfachung vornehmen: a
ist einfach s + q
und e
ist w + d
. Lass uns das tun:
a
sq
e
wd
Auch diese s
und w
werden einfach rausfallen. Alles, was wir tun müssen, ist, diese q
s und d
s nach vorne zu schieben und sie in w
s und s
s selbst zu verwandeln . Wir machen das mit zwei getrennten Schleifen:
+`(.+)q
w$1
+`(.+)d
s$1
Das ist also erledigt. Zeit für die Konvertierung von axialen zu versetzten Koordinaten. Dafür müssen wir die Ziffern kollabieren. Im Moment interessiert uns jedoch nur die linke Seite. Aufgrund der Art q
und Weise, in der wir die s und d
s verarbeitet haben, wissen wir, dass alle s
s auf der linken Seite vor den w
s angezeigt werden. Daher müssen wir nur ein Paar überprüfen, um sie zu reduzieren:
+`sw
Nun die eigentliche Umstellung. Hier ist der Pseudocode aus dem obigen Link:
# convert cube to odd-q offset
col = x
row = z + (x - (x&1)) / 2
Richtig, also die linke Seite ist schon richtig. Die rechte Seite benötigt jedoch den Korrekturterm (x - (x&1)) / 2
. Taking &1
ist dasselbe wie modulo 2. Dies wird im Grunde genommen als x/2
Ganzzahldivision, gerundet gegen minus unendlich, analysiert . Für Positiv x
addieren wir also die Hälfte der Ziffern (abgerundet) und für Negativ x
subtrahieren wir die Hälfte der Ziffern (aufgerundet). Dies lässt sich in Regex überraschend prägnant ausdrücken:
(.*)(\1w?):
$0$2
Aufgrund der Habgier stimmt x
Gruppe 1 für gerade genau mit der Hälfte der Ziffern überein, \1
die andere Hälfte und wir können die ignorieren w?
. Wir fügen , dass die Hälfte nach der :
(die x/2
). Wenn x
es gerade ist, müssen wir zwischen positiv und negativ unterscheiden. Wenn dies x
positiv ist, w?
stimmen die Werte nie überein. Daher müssen die beiden Gruppen immer noch mit der gleichen Anzahl von Ziffern übereinstimmen. Das ist kein Problem, wenn der erste s
einfach übersprungen wird und wir abrunden. Wenn x
negativ und ungerade ist, dann ist die mögliche Übereinstimmung mit \1
(die Hälfte der x
abgerundeten) und dieser optional w
. Da beide in Gruppen zusammengefasst sind 2
, schreiben wir x/2
mit der aufgerundeten Größe (je nach Bedarf).
+`sw|ws
Jetzt reduzieren wir die Ziffern auf der rechten Seite. Dieses Mal kennen wir die Reihenfolge der s
und nicht w
, daher müssen wir beide Paare berücksichtigen.
w+
-$0
Beide Teile werden jetzt auf eine einzige wiederholte Ziffer (oder gar nichts) reduziert. Wenn diese Ziffer ist w
, fügen wir ein Minuszeichen vor.
\w
1
Und schließlich verwandeln wir uns sowohl in eine w
als auch s
in eine einzige vernünftige unäre Ziffer. (Ich nehme an, ich könnte ein Byte speichern, indem ich w
oder s
als unäre Ziffer verwende, aber das scheint ein bisschen lang zu sein.)