Võng mạc , 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
Đầu ra là đơn nhất, cách nhau bởi một dấu hai chấm. Điều đó có nghĩa là bạn sẽ không thực sự nhìn thấy các số 0 trong đầu ra (mặc dù sự hiện diện của dấu hai chấm sẽ cho bạn biết tọa độ nào trong hai tọa độ bằng 0, nếu chỉ có một).
Hãy thử trực tuyến!
Điều này thực sự thú vị và cuối cùng là ngắn đáng ngạc nhiên. :)
Giải trình
Một số nền tảng đầu tiên. Có một số hệ tọa độ để mô tả lưới lục giác. Một trong những yêu cầu sử dụng tọa độ bù. Điều đó về cơ bản giống như tọa độ lưới hình chữ nhật, ngoại trừ một trục "chao đảo" một chút. Cụ thể, câu hỏi yêu cầu bố cục "lẻ-q" được hiển thị trên trang được liên kết. Hệ thống tọa độ này hơi khó chịu khi làm việc, bởi vì cách tọa độ thay đổi trong quá trình di chuyển không chỉ phụ thuộc vào hướng di chuyển mà còn phụ thuộc vào vị trí hiện tại.
Một hệ tọa độ khác sử dụng tọa độ trục. Về cơ bản, nó tưởng tượng hexgrid như một lát chéo qua một thể tích hình khối và sử dụng hai trong số các trục (ví dụ x và z) để tìm vị trí trên mặt phẳng 2D. Trên lưới hex, điều đó có nghĩa là hai trục tạo thành một góc 60 (hoặc 120) độ. Hệ thống này ít trực quan hơn một chút nhưng dễ làm việc hơn, vì mọi hướng tương ứng với một vectơ "delta" cố định. (Để được giải thích rõ hơn về cách đến hệ thống tọa độ này, hãy kiểm tra liên kết và các sơ đồ và hình ảnh động đáng yêu ở đó.)
Vì vậy, đây là những gì chúng ta sẽ làm: chúng ta tính toán chuyển động theo tọa độ trục (chăm sóc xoay như được đề xuất trong thử thách, bằng cách ánh xạ lại ý nghĩa của các lệnh) và khi hoàn thành, chúng ta chuyển đổi trục sang bù lẻ-q tọa độ.
Sáu di chuyển ánh xạ tới các vectơ delta sau trong tọa độ trục (xz):
q => (-1, 0)
w => ( 0, -1)
e => ( 1, -1)
d => ( 1, 0)
s => ( 0, 1)
a => (-1, 1)
Đợi đã, đây là Retina, chúng ta sẽ phải làm việc với những con số đơn nguyên. Làm thế nào để chúng ta làm việc với số unary âm? Ý tưởng là sử dụng hai chữ số khác nhau. Một đại diện +1
và đại diện khác -1
. Điều đó có nghĩa là bất kể chúng ta muốn thêm hay bớt 1
vị trí hiện tại, chúng ta luôn có thể làm như vậy bằng cách thêm một chữ số. Khi chúng ta hoàn thành, chúng ta thu gọn kết quả thành độ lớn của nó (của chữ số tương ứng) bằng cách hủy các chữ số cân bằng. Sau đó, chúng tôi tìm ra dấu hiệu dựa trên chữ số còn lại và thay thế tất cả các chữ số bằng 1
.
Kế hoạch là xây dựng các thành phần trục x và z ở bên trái và bên phải của một :
(như một dấu phân cách), ở phía trước của đầu vào. w
và s
sẽ thêm vào phía bên tay phải. q
và d
sẽ thêm vào phía bên trái, e
và a
sẽ thêm vào cả hai bên. Vì w
và s
đã ở phía bên phải của :
(sẽ đi phía trước), nên chúng ta sẽ sử dụng chúng tương ứng là các chữ số -1
và +1
chữ số.
Chúng ta hãy đi qua mã.
R
5$*r
Chúng tôi bắt đầu bằng cách biến mỗi R
thành năm r
s. Tất nhiên, một lần rẽ trái giống như năm lượt rẽ phải trên lưới hex và bằng cách đó, chúng ta có thể nhân đôi rất nhiều trong bước ánh xạ lại.
T`aq\we\ds`so`r.+
Đây là giai đoạn chuyển ngữ làm quay sáu lệnh, nếu chúng được tìm thấy sau lệnh đầu tiên r
(do đó xử lý lệnh đầu tiên r
). w
và d
cần phải được trốn thoát để ngăn chúng mở rộng thành các lớp nhân vật. Việc o
chèn tập hợp nguồn vào tập hợp đích sẽ lưu một bó byte cho các tác vụ xoay vòng này. Do đó, ánh xạ ký tự là:
aqweds
saqweds
nơi cuối cùng s
trong hàng thứ hai có thể đơn giản được bỏ qua.
)`r(.*)
$1
Điều này loại bỏ chuỗi đầu tiên r
khỏi chuỗi, vì nó đã được xử lý (tôi ước tôi đã thực hiện các giới hạn thay thế ...). Điều này )
cũng cho Retina chạy tất cả các giai đoạn cho đến giai đoạn này trong một vòng lặp cho đến khi chuỗi ngừng thay đổi. Ở các lần lặp lại tiếp theo, giai đoạn đầu tiên là không có op vì không còn R
s và giai đoạn thứ hai sẽ áp dụng một phép quay khác miễn là r
còn lại s trong chuỗi.
Khi chúng ta hoàn thành, chúng ta đã ánh xạ tất cả các lệnh theo hướng chúng tương ứng trên lưới không được bảo vệ và có thể bắt đầu xử lý chúng. Tất nhiên chuyển động này chỉ là một tổng của các vectơ delta đó và các khoản tiền là giao hoán, vì vậy chúng ta không thực sự xử lý chúng theo cách nào mà các phép quay đã bị loại bỏ.
^
:
Chèn dấu phân cách tọa độ ở phía trước.
Bây giờ chúng tôi không thực sự cần phải xử lý s
và w
. Chúng là chữ số của chúng tôi +1
và -1
chúng đã ở phía chính xác :
nên cuối cùng chúng sẽ rơi ra theo yêu cầu. Chúng ta có thể thực hiện một sự đơn giản hóa khác: a
đơn giản s + q
và e
là w + d
. Hãy làm điều đó:
a
sq
e
wd
Một lần nữa, những người s
và w
sẽ bỏ học. Tất cả chúng ta cần phải làm là di chuyển những q
s và d
s vào phía trước và biến chúng thành w
s và s
s bản thân. Chúng tôi làm điều đó với hai vòng riêng biệt:
+`(.+)q
w$1
+`(.+)d
s$1
Vậy là xong. Thời gian chuyển đổi từ tọa độ trục sang tọa độ bù. Cho rằng chúng ta cần thu gọn các chữ số. Tuy nhiên, bây giờ chúng tôi chỉ quan tâm đến phía bên tay trái. Do cách chúng tôi xử lý các q
s và d
s, chúng tôi biết rằng tất cả các s
s ở phía bên trái sẽ xuất hiện trước bất kỳ w
s nào , vì vậy chúng tôi chỉ cần kiểm tra một cặp để thu gọn chúng:
+`sw
Bây giờ chuyển đổi thực tế. Đây là mã giả, được lấy từ liên kết ở trên:
# convert cube to odd-q offset
col = x
row = z + (x - (x&1)) / 2
Phải, vì vậy phía bên trái đã chính xác. Phía bên tay phải cần thuật ngữ điều chỉnh (x - (x&1)) / 2
mặc dù. Lấy &1
giống như modulo 2. Về cơ bản, phân tích này là x/2
, phân chia số nguyên, được làm tròn về phía âm vô cực. Vì vậy, đối với số dương x
, chúng ta cộng một nửa số chữ số (làm tròn xuống) và đối với số âm x
, chúng ta trừ đi một nửa số chữ số (làm tròn lên). Điều này có thể được thể hiện một cách đáng ngạc nhiên chính xác trong regex:
(.*)(\1w?):
$0$2
Do sự tham lam, cho chẵn x
, nhóm 1 sẽ khớp chính xác một nửa chữ số, \1
nửa còn lại và chúng ta có thể bỏ qua w?
. Chúng tôi chèn một nửa sau :
(đó là x/2
). Nếu x
là chẵn thì chúng ta cần phân biệt dương và âm. Nếu x
là dương, thì w?
sẽ không bao giờ khớp, vì vậy hai nhóm vẫn sẽ phải khớp cùng một số chữ số. Điều đó không có vấn đề gì nếu lần đầu tiên s
bị bỏ qua, vì vậy chúng tôi làm tròn xuống. Nếu x
là âm và lẻ, thì kết quả khớp có thể là với \1
(một nửa số x
được làm tròn xuống) và tùy chọn đó w
. Vì cả hai đều đi vào nhóm 2
, chúng tôi sẽ viết x/2
với cường độ được làm tròn (theo yêu cầu).
+`sw|ws
Bây giờ chúng tôi thu gọn các chữ số ở phía bên tay phải. Lần này, chúng tôi không biết thứ tự của s
và w
, vì vậy chúng tôi cần tính đến cả hai cặp.
w+
-$0
Cả hai phần bây giờ được giảm xuống một chữ số lặp lại (hoặc không có gì). Nếu chữ số đó là w
, chúng tôi chèn một dấu trừ ở phía trước.
\w
1
Và cuối cùng chúng ta biến cả thành w
và s
thành một chữ số unary hợp lý duy nhất. (Tôi cho rằng tôi có thể lưu một byte bằng cách sử dụng w
hoặc s
dưới dạng chữ số đơn, nhưng điều đó có vẻ hơi căng.)