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 +1và đạ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 1vị 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. wvà ssẽ thêm vào phía bên tay phải. qvà dsẽ thêm vào phía bên trái, evà asẽ thêm vào cả hai bên. Vì wvà 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ố -1và +1chữ 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 Rthành năm rs. 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). wvà dcầ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 ochè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 strong 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 rkhỏ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 Rs và giai đoạn thứ hai sẽ áp dụng một phép quay khác miễn là rcò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ý svà w. Chúng là chữ số của chúng tôi +1và -1chú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 + qvà elà w + d. Hãy làm điều đó:
a
sq
e
wd
Một lần nữa, những người svà wsẽ bỏ học. Tất cả chúng ta cần phải làm là di chuyển những qs và ds vào phía trước và biến chúng thành ws và ss 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 qs và ds, chúng tôi biết rằng tất cả các ss ở phía bên trái sẽ xuất hiện trước bất kỳ ws 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)) / 2mặc dù. Lấy &1giố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ố, \1nử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 xlà chẵn thì chúng ta cần phân biệt dương và âm. Nếu xlà 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 sbị bỏ qua, vì vậy chúng tôi làm tròn xuống. Nếu xlà â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/2vớ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 svà 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 wvà sthà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 whoặc sdưới dạng chữ số đơn, nhưng điều đó có vẻ hơi căng.)