Tôi giới thiệu với bạn, 3% đầu tiên của trình thông dịch tự Hexagony ...
|./...\..._..>}{<$}=<;>'<..../;<_'\{*46\..8._~;/;{{;<..|M..'{.>{{=.<.).|.."~....._.>(=</.\=\'$/}{<}.\../>../..._>../_....@/{$|....>...</..~\.>,<$/'";{}({/>-'(<\=&\><${~-"~<$)<....'.>=&'*){=&')&}\'\'2"'23}}_}&<_3.>.'*)'-<>{=/{\*={(&)'){\$<....={\>}}}\&32'-<=._.)}=)+'_+'&<
Hãy thử trực tuyến! Bạn cũng có thể tự chạy nó, nhưng sẽ mất khoảng 5-10 giây.
Về nguyên tắc, điều này có thể phù hợp với độ dài 9 bên (cho số điểm từ 217 trở xuống), bởi vì điều này chỉ sử dụng 201 lệnh và phiên bản không được viết mà tôi đã viết trước (trên chiều dài 30) chỉ cần 178 lệnh. Tuy nhiên, tôi khá chắc chắn rằng sẽ mất nhiều thời gian để thực sự làm mọi thứ phù hợp, vì vậy tôi không chắc liệu tôi có thực sự thử nó hay không.
Cũng có thể chơi golf này một chút trong kích thước 10 bằng cách tránh sử dụng một hoặc hai hàng cuối cùng, để có thể bỏ qua các dấu không có dấu, nhưng điều đó đòi hỏi phải viết lại đáng kể, như một trong những đường dẫn đầu tiên tham gia sử dụng góc dưới bên trái.
Giải trình
Hãy bắt đầu bằng cách mở mã và chú thích các đường dẫn luồng điều khiển:
Điều đó vẫn còn khá lộn xộn, vì vậy đây là sơ đồ tương tự cho mã "không được mã hóa" mà tôi đã viết đầu tiên (trên thực tế, đây là chiều dài 20 và ban đầu tôi đã viết mã ở độ dài 30 nhưng nó rất thưa thớt Không cải thiện khả năng đọc, vì vậy tôi đã nén nó chỉ một chút để làm cho kích thước hợp lý hơn một chút):
Nhấn vào đây để xem phiên bản lớn hơn.
Các màu hoàn toàn giống nhau ngoài một vài chi tiết rất nhỏ, các lệnh không điều khiển luồng cũng hoàn toàn giống nhau. Vì vậy, tôi sẽ giải thích cách thức hoạt động của nó dựa trên phiên bản không được chỉnh sửa và nếu bạn thực sự muốn biết cách chơi golf, bạn có thể kiểm tra phần nào tương ứng với phần nào trong hình lục giác lớn hơn. (Điểm hấp dẫn duy nhất là mã đánh gôn bắt đầu bằng gương để mã thực tế bắt đầu ở góc phải sang trái.)
Thuật toán cơ bản gần giống với câu trả lời của tôi . Có hai điểm khác biệt:
- Thay vì giải phương trình số lục giác trung tâm, tôi chỉ tính các số lục giác trung tâm liên tiếp cho đến khi một số bằng hoặc lớn hơn độ dài của đầu vào. Điều này là do Hexagony không có cách đơn giản để tính căn bậc hai.
- Thay vì đệm ngay đầu vào bằng no-ops ngay lập tức, tôi kiểm tra sau nếu tôi đã sử dụng hết các lệnh trong đầu vào và in
.
thay thế nếu tôi có.
Điều đó có nghĩa là ý tưởng cơ bản nắm bắt được:
- Đọc và lưu trữ chuỗi đầu vào trong khi tính toán độ dài của nó.
- Tìm chiều dài cạnh nhỏ nhất
N
(và số lục giác trung tâm tương ứng hex(N)
) có thể chứa toàn bộ đầu vào.
- Tính đường kính
2N-1
.
- Đối với mỗi dòng, tính toán thụt lề và số lượng ô (tính tổng
2N-1
). In thụt lề, in các ô (sử dụng .
nếu đầu vào đã hết), in một nguồn cấp dữ liệu.
Lưu ý rằng chỉ có no-op nên mã thực tế bắt đầu ở góc bên trái (cái $
, nhảy qua >
, vì vậy chúng ta thực sự bắt đầu trên ,
con đường màu xám đen).
Đây là lưới bộ nhớ ban đầu:
Vì vậy, con trỏ bộ nhớ bắt đầu trên cạnh đầu vào có nhãn , chỉ về phía Bắc. ,
đọc một byte từ STDIN hoặc -1
nếu chúng ta nhấn EOF vào cạnh đó. Do đó, <
quyền sau là điều kiện cho dù chúng ta đã đọc tất cả các đầu vào. Bây giờ chúng ta hãy ở trong vòng lặp đầu vào. Mã tiếp theo chúng tôi thực hiện là
{&32'-
Điều này ghi 32 vào không gian được dán nhãn cạnh , và sau đó trừ nó khỏi giá trị đầu vào trong cạnh có nhãn diff . Lưu ý rằng điều này không bao giờ có thể âm bởi vì chúng tôi đảm bảo rằng đầu vào chỉ chứa ASCII có thể in được. Nó sẽ bằng không khi đầu vào là một khoảng trắng. (Như Timwi chỉ ra, điều này vẫn hoạt động nếu đầu vào có thể chứa các dòng hoặc tab, nhưng nó cũng sẽ loại bỏ tất cả các ký tự không thể in khác có mã ký tự nhỏ hơn 32.) Trong trường hợp đó, <
làm chệch hướng con trỏ lệnh (IP) và con đường màu xám nhạt được thực hiện. Đường dẫn đó chỉ đơn giản là đặt lại vị trí của MP {=
và sau đó đọc ký tự tiếp theo - do đó, khoảng trắng được bỏ qua. Mặt khác, nếu ký tự không phải là khoảng trắng, chúng ta thực thi
=}}})&'+'+)=}
Điều này đầu tiên di chuyển xung quanh hình lục giác thông qua cạnh chiều dài cho đến khi nó đối diện với cạnh khác , với =}}}
. Sau đó, nó sao chép giá trị từ đối diện cạnh chiều dài vào cạnh chiều dài và tăng nó với )&'+'+)
. Chúng ta sẽ thấy trong một giây tại sao điều này có ý nghĩa. Cuối cùng, chúng tôi di chuyển một cạnh mới với =}
:
(Các giá trị cạnh cụ thể là từ trường hợp thử nghiệm cuối cùng được đưa ra trong thử thách.) Tại thời điểm này, vòng lặp lặp lại, nhưng với mọi thứ đã dịch chuyển một hình lục giác về phía đông bắc. Vì vậy, sau khi đọc một nhân vật khác, chúng ta nhận được điều này:
Bây giờ bạn có thể thấy rằng chúng ta đang dần viết đầu vào (trừ khoảng trắng) dọc theo đường chéo phía đông bắc, với các ký tự ở mọi cạnh khác và độ dài cho đến ký tự đó được lưu trữ song song với chiều dài được dán nhãn .
Khi chúng ta hoàn thành vòng lặp đầu vào, bộ nhớ sẽ trông như thế này (nơi tôi đã gắn nhãn một vài cạnh mới cho phần tiếp theo):
Đây %
là ký tự cuối cùng chúng ta đọc, 29
là số lượng ký tự không phải không gian chúng ta đọc. Bây giờ chúng tôi muốn tìm chiều dài của hình lục giác. Đầu tiên, có một số mã khởi tạo tuyến tính trong đường dẫn màu lục / xám đậm:
=&''3{
Ở đây, =&
sao chép chiều dài (29 trong ví dụ của chúng tôi) vào chiều dài được dán nhãn . Sau đó ''3
di chuyển đến cạnh có nhãn 3 và đặt giá trị của nó thành 3
(mà chúng ta chỉ cần là hằng số trong tính toán). Cuối cùng {
di chuyển đến cạnh có nhãn N (N-1) .
Bây giờ chúng ta vào vòng lặp màu xanh. Vòng lặp này tăng N
(được lưu trữ trong ô có nhãn N ) sau đó tính số lục giác ở giữa và trừ nó khỏi độ dài đầu vào. Mã tuyến tính thực hiện điều đó là:
{)')&({=*'*)'-
Ở đây, {)
di chuyển đến và gia số N . ')&(
di chuyển đến cạnh có nhãn N-1 , sao chép N
ở đó và giảm nó. {=*
tính sản phẩm của họ theo N (N-1) . '*)
nhân số đó với hằng số 3
và tăng kết quả trong cạnh có nhãn hex (N) . Theo dự kiến, đây là số lục giác trung tâm thứ N. Cuối cùng '-
tính toán sự khác biệt giữa đó và chiều dài đầu vào. Nếu kết quả là dương, độ dài cạnh chưa đủ lớn và vòng lặp lặp lại (trong đó }}
di chuyển MP trở lại cạnh có nhãn N (N-1) ).
Khi độ dài cạnh đủ lớn, chênh lệch sẽ bằng 0 hoặc âm và chúng ta nhận được điều này:
Trước hết, bây giờ có đường dẫn màu xanh tuyến tính thực sự dài, thực hiện một số khởi tạo cần thiết cho vòng lặp đầu ra:
{=&}}}32'"2'=&'*){=&')&}}
Việc {=&
bắt đầu bằng cách sao chép kết quả ở cạnh khác vào cạnh dài , vì sau này chúng ta cần một cái gì đó không tích cực ở đó. }}}32
ghi 32 vào không gian được dán nhãn . '"2
ghi một hằng số 2 vào cạnh không ghi trên diff . '=&
bản sao N-1
vào cạnh thứ hai với cùng một nhãn. '*)
nhân nó lên 2 và tăng nó để chúng ta có được giá trị chính xác ở cạnh có nhãn 2N-1 ở trên cùng. Đây là đường kính của hình lục giác. {=&')&
sao chép đường kính vào cạnh khác có nhãn 2N-1 . Cuối cùng }}
di chuyển trở lại cạnh có nhãn 2N-1 ở trên cùng.
Chúng ta hãy dán lại các cạnh:
Cạnh chúng ta hiện đang ở (vẫn giữ đường kính của hình lục giác) sẽ được sử dụng để lặp qua các dòng của đầu ra. Các cạnh được gắn nhãn thụt lề sẽ tính toán có bao nhiêu khoảng trống cần thiết trên dòng hiện tại. Các ô có nhãn cạnh sẽ được sử dụng để lặp lại số lượng ô trong dòng hiện tại.
Bây giờ chúng ta đang trên con đường màu hồng tính toán thụt lề . ('-
giảm các dòng lặp và trừ nó từ N-1 (vào cạnh thụt lề ). Nhánh màu xanh / xám ngắn trong mã chỉ đơn giản là tính mô-đun của kết quả ( ~
phủ định giá trị nếu nó âm hoặc bằng 0 và không có gì xảy ra nếu nó dương). Phần còn lại của đường màu hồng là "-~{
phép trừ vết lõm từ đường kính vào cạnh ô và sau đó di chuyển trở lại cạnh thụt .
Con đường màu vàng bẩn bây giờ in vết lõm. Nội dung vòng lặp thực sự chỉ là
'";{}(
Nơi '"
di chuyển đến cạnh không gian , ;
in nó, {}
di chuyển trở lại thụt lề và (
giảm nó.
Khi chúng ta thực hiện xong, đường dẫn màu xám đen (thứ hai) sẽ tìm kiếm ký tự tiếp theo để in. Các =}
di chuyển trong vị trí (có nghĩa là, trên các cạnh tế bào , chỉ về phía Nam). Sau đó, chúng tôi có một vòng lặp rất chặt {}
, chỉ cần di chuyển xuống hai cạnh theo hướng Tây Nam, cho đến khi chúng tôi chạm vào cuối chuỗi được lưu trữ:
Lưu ý rằng tôi đã di chuyển một cạnh có EOF? . Khi chúng tôi đã xử lý ký tự này, chúng tôi sẽ làm cho cạnh đó trở nên âm, để {}
vòng lặp sẽ chấm dứt ở đây thay vì lần lặp tiếp theo:
Trong mã, chúng ta ở cuối con đường màu xám đen, nơi '
di chuyển lùi một bước vào ký tự đầu vào. Nếu tình huống là một trong hai sơ đồ cuối cùng (nghĩa là vẫn còn một ký tự từ đầu vào mà chúng ta chưa in), thì chúng ta đang đi theo con đường màu xanh lá cây (cái dưới cùng, dành cho những người không tốt với màu xanh lá cây và màu xanh da trời). Điều đó khá đơn giản: ;
in chính nhân vật. '
di chuyển đến cạnh không gian tương ứng vẫn giữ 32 từ trước đó và ;
in không gian đó. Sau đó {~
làm cho EOF của chúng tôi ? phủ định cho lần lặp tiếp theo, '
di chuyển lùi một bước để chúng ta có thể quay lại đầu phía tây bắc của chuỗi bằng một }{
vòng lặp chặt chẽ khác . Mà kết thúc trên chiều dàiô (ô không dương dưới hex (N) . Cuối cùng }
di chuyển trở lại cạnh ô .
Nếu chúng ta đã cạn kiệt đầu vào, thì vòng lặp tìm kiếm EOF là gì? sẽ thực sự chấm dứt ở đây:
Trong trường hợp đó, '
di chuyển lên ô dài và thay vào đó, chúng ta sẽ chọn đường dẫn màu xanh lam nhạt (trên cùng), in ra một chữ không có op. Mã trong nhánh này là tuyến tính:
{*46;{{;{{=
Người {*46;
viết 46 vào cạnh có nhãn no-op và in nó (tức là một khoảng thời gian). Sau đó {{;
di chuyển đến cạnh không gian và in nó. Việc {{=
di chuyển trở lại cạnh các ô cho lần lặp tiếp theo.
Tại thời điểm này, các đường dẫn nối lại với nhau và làm (
giảm cạnh của các ô . Nếu iterator chưa bằng 0, chúng ta sẽ chọn đường dẫn màu xám nhạt, chỉ đơn giản là đảo ngược hướng của MP =
và sau đó đi tìm ký tự tiếp theo để in.
Mặt khác, chúng ta đã đi đến cuối dòng hiện tại và IP sẽ đi theo con đường màu tím thay thế. Đây là những gì lưới bộ nhớ trông giống như tại thời điểm đó:
Đường dẫn màu tím chứa điều này:
=M8;~'"=
Sự =
đảo ngược hướng của MP một lần nữa. M8
đặt giá trị của nó thành 778
(vì mã ký tự M
là 77
và các chữ số sẽ tự nối với giá trị hiện tại). Điều này xảy ra 10 (mod 256)
, vì vậy khi chúng tôi in nó ;
, chúng tôi nhận được một nguồn cấp dữ liệu. Sau đó ~
làm cho cạnh âm trở lại, '"
di chuyển trở lại cạnh đường và =
đảo ngược MP một lần nữa.
Bây giờ nếu cạnh đường bằng 0, chúng ta đã hoàn thành. IP sẽ đi theo con đường màu đỏ (rất ngắn), trong đó @
chấm dứt chương trình. Mặt khác, chúng ta tiếp tục trên con đường màu tím lặp lại thành màu hồng để in một dòng khác.
Sơ đồ điều khiển được tạo bằng HexagonyColorer của Timwi's . Sơ đồ bộ nhớ được tạo bằng trình gỡ lỗi trực quan trong IDE bí truyền của anh ấy .
abc`defg
thực sự sẽ trở thành pastebin.com/ZrdJmHiR