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 +1und der andere repräsentiert -1. Das heißt, unabhängig davon, ob wir 1von 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 . wund swird auf der rechten Seite hinzugefügt. qund dwerden auf der linken Seite hinzugefügt , und eund awerden auf beiden Seiten hinzugefügt. Da wund sbereits auf der richtigen Seite von :(die voran gehen wird), werden wir diese als -1und +1Ziffern verwenden.
Lass uns den Code durchgehen.
R
5$*r
Wir fangen damit an, dass wir jeweils Rfünf rs 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). wund dmüssen entkommen werden, um zu verhindern, dass sie in Charakterklassen expandieren. Der ofü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 sin der zweiten Reihe einfach ignoriert werden kann.
)`r(.*)
$1
Dadurch wird die erste rZeichenfolge 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 Rs vorhanden sind und die zweite Stufe eine weitere Drehung anwendet, solange noch rs 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 sund w. Sie sind unsere +1und die -1Ziffern und befinden sich bereits auf der richtigen Seite, :sodass sie am Ende nur wie erforderlich aussteigen. Wir können eine weitere Vereinfachung vornehmen: aist einfach s + qund eist w + d. Lass uns das tun:
a
sq
e
wd
Auch diese sund wwerden einfach rausfallen. Alles, was wir tun müssen, ist, diese qs und ds nach vorne zu schieben und sie in ws und ss 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 qund Weise, in der wir die s und ds verarbeitet haben, wissen wir, dass alle ss auf der linken Seite vor den ws 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 &1ist dasselbe wie modulo 2. Dies wird im Grunde genommen als x/2Ganzzahldivision, gerundet gegen minus unendlich, analysiert . Für Positiv xaddieren wir also die Hälfte der Ziffern (abgerundet) und für Negativ xsubtrahieren 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 xGruppe 1 für gerade genau mit der Hälfte der Ziffern überein, \1die andere Hälfte und wir können die ignorieren w?. Wir fügen , dass die Hälfte nach der :(die x/2). Wenn xes gerade ist, müssen wir zwischen positiv und negativ unterscheiden. Wenn dies xpositiv 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 seinfach übersprungen wird und wir abrunden. Wenn xnegativ und ungerade ist, dann ist die mögliche Übereinstimmung mit \1(die Hälfte der xabgerundeten) und dieser optional w. Da beide in Gruppen zusammengefasst sind 2, schreiben wir x/2mit 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 sund 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 wals auch sin eine einzige vernünftige unäre Ziffer. (Ich nehme an, ich könnte ein Byte speichern, indem ich woder sals unäre Ziffer verwende, aber das scheint ein bisschen lang zu sein.)