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
Keluaran dalam unary, dipisahkan oleh titik dua. Itu berarti Anda tidak akan benar-benar melihat nol di output (walaupun keberadaan titik dua akan memberi tahu Anda yang mana dari dua koordinat tersebut nol, jika hanya ada satu).
Cobalah online!
Ini benar-benar menyenangkan dan akhirnya menjadi sangat singkat. :)
Penjelasan
Beberapa latar belakang terlebih dahulu. Ada beberapa sistem koordinat untuk menggambarkan kisi heksagonal. Yang meminta menggunakan koordinat offset. Itu pada dasarnya seperti koordinat kotak persegi panjang, kecuali bahwa satu sumbu "bergoyang" sedikit. Secara khusus, pertanyaannya menanyakan tata letak "odd-q" yang ditunjukkan pada halaman yang ditautkan. Sistem koordinat ini agak menjengkelkan untuk digunakan, karena bagaimana koordinat berubah selama gerakan tidak hanya bergantung pada arah gerakan tetapi juga pada posisi saat ini.
Sistem koordinat lain menggunakan koordinat aksial. Itu pada dasarnya membayangkan hexgrid sebagai irisan diagonal melalui volume kubus, dan menggunakan dua sumbu (misalnya x dan z) untuk menemukan posisi pada bidang 2D. Pada kisi hex, itu berarti bahwa kedua sumbu membentuk sudut 60 (atau 120) derajat. Sistem ini sedikit kurang intuitif tetapi jauh lebih mudah untuk dikerjakan, karena setiap arah sesuai dengan vektor "delta" yang diperbaiki. (Untuk penjelasan yang lebih baik tentang cara tiba di sistem koordinat ini, lihat tautan dan diagram serta animasi yang indah di sana.)
Jadi inilah yang akan kita lakukan: kita menghitung pergerakan dalam koordinat aksial (menjaga rotasi seperti yang disarankan dalam tantangan, dengan memetakan kembali makna perintah), dan ketika kita selesai kita mengonversi aksial ke aneh-q offset koordinat.
Enam bergerak peta ke vektor delta berikut di (xz) koordinat aksial:
q => (-1, 0)
w => ( 0, -1)
e => ( 1, -1)
d => ( 1, 0)
s => ( 0, 1)
a => (-1, 1)
Tunggu, ini Retina, kita harus bekerja dengan angka-angka unary. Bagaimana cara kita bekerja dengan angka unary negatif? Idenya adalah menggunakan dua digit berbeda. Satu mewakili +1dan yang lainnya mewakili -1. Itu berarti terlepas dari apakah kita ingin menambah atau mengurangi 1posisi sekarang, kita selalu dapat melakukannya dengan menambahkan angka. Setelah selesai, kami menciutkan hasilnya menjadi besarnya (dari angka yang sesuai) dengan membatalkan angka seimbang. Kemudian kami mencari tanda berdasarkan digit yang tersisa, dan mengganti semua digit 1.
Rencananya adalah untuk membangun komponen aksial x dan z ke kiri dan kanan a :(sebagai pemisah), di depan input. wdan sakan ditambahkan ke sisi kanan. qdan dakan menambah ke sisi kiri, dan edan aakan menambah ke kedua sisi. Karena wdan ssudah berada di sisi yang benar dari :(yang akan berada di depan), kita akan menggunakannya sebagai masing-masing -1dan +1digit.
Mari kita lihat kodenya.
R
5$*r
Kita mulai dengan mengubah masing R- masing menjadi lima r. Tentu saja, satu belokan kiri sama dengan lima belokan kanan pada hex grid, dan dengan melakukan itu kita dapat banyak duplikasi pada langkah pemetaan ulang.
T`aq\we\ds`so`r.+
Ini adalah tahap transliterasi yang memutar enam perintah, jika ditemukan setelah yang pertama r(dengan demikian memproses yang pertama r). wdan dperlu melarikan diri untuk mencegah mereka berkembang ke kelas karakter. The omenyisipkan sumber set ke target yang ditetapkan yang menyimpan banyak byte untuk tugas-tugas rotasi ini. Karenanya pemetaan karakter:
aqweds
saqweds
di mana yang terakhir sdi baris kedua bisa diabaikan begitu saja.
)`r(.*)
$1
Ini menghapus yang pertama rdari string, karena sudah diproses (saya berharap saya sudah menerapkan batas substitusi ...). The )juga memberitahu Retina untuk menjalankan semua tahapan hingga satu ini dalam satu lingkaran sampai string berhenti berubah. Pada iterasi berikutnya, tahap pertama adalah no-op karena tidak ada lagi Rs dan tahap kedua akan menerapkan rotasi lain selama ada yang rtersisa di string.
Setelah selesai, kami telah memetakan semua perintah ke arah yang sesuai pada kisi yang tidak diputar dan dapat mulai memprosesnya. Tentu saja pergerakan ini hanyalah jumlah dari vektor-vektor delta itu, dan penjumlahannya bersifat komutatif, jadi tidak masalah dalam urutan mana kita memprosesnya sekarang karena rotasi telah dihilangkan.
^
:
Masukkan pembatas koordinat di depan.
Sekarang kita tidak benar-benar perlu memproses sdan w. Mereka adalah milik kita +1dan -1angka dan mereka sudah berada di sisi yang benar :sehingga mereka hanya akan keluar seperti yang dibutuhkan pada akhirnya. Kita dapat membuat penyederhanaan lain: asederhana s + qdan esedang w + d. Ayo lakukan itu:
a
sq
e
wd
Sekali lagi, itu sdan whanya akan putus. Yang perlu kita lakukan adalah memindahkan qitu dan dke depan dan mengubahnya menjadi wdan situ sendiri. Kami melakukannya dengan dua loop terpisah:
+`(.+)q
w$1
+`(.+)d
s$1
Jadi sudah selesai. Saatnya konversi dari koordinat aksial ke offset. Untuk itu kita perlu menciutkan digit. Namun, untuk saat ini kami hanya peduli dengan sisi kiri. Karena cara kami memproses huruf qs dan ds, kami tahu bahwa semua shuruf s di sisi kiri akan muncul di depan huruf ws, jadi kami hanya perlu memeriksa satu pasangan untuk menciutkannya:
+`sw
Sekarang konversi yang sebenarnya. Ini adalah kodesemu, diambil dari tautan di atas:
# convert cube to odd-q offset
col = x
row = z + (x - (x&1)) / 2
Benar, jadi sisi kiri sudah benar. Sisi kanan membutuhkan jangka waktu koreksi (x - (x&1)) / 2. Pengambilan &1sama dengan modulo 2. Ini pada dasarnya diurai sebagai x/2, pembagian bilangan bulat, dibulatkan ke arah minus tanpa batas. Jadi untuk positif x, kita tambahkan setengah jumlah digit (dibulatkan ke bawah), dan untuk negatif x, kita kurangi setengah jumlah digit (dibulatkan ke atas). Hal ini dapat diekspresikan secara mengejutkan dalam regex:
(.*)(\1w?):
$0$2
Karena keserakahan, untuk genap x, grup 1 akan cocok persis setengah digit, \1separuh lainnya dan kita bisa mengabaikannya w?. Kami memasukkan setengah setelah :(yang x/2). Jika xgenap, maka kita perlu membedakan positif dan negatif. Jika xpositif, maka w?tidak akan pernah cocok, sehingga kedua kelompok masih harus mencocokkan jumlah digit yang sama. Itu tidak masalah jika yang pertama shanya dilewati, jadi kami membulatkannya. Jika xnegatif dan ganjil, maka kemungkinan kecocokannya adalah dengan \1(setengah xdibulatkan ke bawah) dan opsional itu w. Karena keduanya masuk dalam grup 2, kita akan menulis x/2dengan magnitudo yang dibulatkan (sesuai kebutuhan).
+`sw|ws
Sekarang kita meruntuhkan angka di sisi kanan. Kali ini, kami tidak tahu urutan sdan w, jadi kami harus memperhitungkan kedua pasangan.
w+
-$0
Kedua bagian sekarang dikurangi menjadi satu digit berulang (atau tidak sama sekali). Jika digit itu adalah w, kami menyisipkan tanda minus di depan.
\w
1
Dan akhirnya kita mengubah keduanya menjadi wdan smenjadi satu digit unary yang masuk akal. (Saya kira saya bisa menyimpan byte dengan menggunakan watau ssebagai digit unary, tapi sepertinya sedikit peregangan.)