Sześciokąt , 920 722 271 bajtów
Mówisz, że jest sześć różnych rodzajów pętli owocowych? To, co Hexagony została wykonana za.
){r''o{{y\p''b{{g''<.{</"&~"&~"&<_.>/{.\.....~..&.>}<.._...=.>\<=..}.|>'%<}|\.._\..>....\.}.><.|\{{*<.>,<.>/.\}/.>...\'/../==.|....|./".<_>){{<\....._>\'=.|.....>{>)<._\....<..\..=.._/}\~><.|.....>e''\.<.}\{{\|./<../e;*\.@=_.~><.>{}<><;.(~.__..>\._..>'"n{{<>{<...="<.>../
Okej, nie było. O Boże, co ja sobie zrobiłem ...
Ten kod jest teraz sześciokątem o długości boku 10 (zaczął od 19). Prawdopodobnie może być jeszcze trochę w golfa, może nawet do rozmiaru 9, ale myślę, że moja praca została wykonana tutaj ... Dla odniesienia, w źródle znajduje się 175 faktycznych poleceń, z których wiele jest potencjalnie niepotrzebnymi kopiami lustrzanymi (lub zostały dodane, aby anulować wydać polecenie ze ścieżki krzyżowej).
Pomimo pozornej liniowości kod jest w rzeczywistości dwuwymiarowy: sześciokąt przekształci go w zwykły sześciokąt (co jest również poprawnym kodem, ale wszystkie białe znaki są opcjonalne w sześciokącie). Oto rozwinięty kod w całym ... no cóż, nie chcę mówić „piękno”:
) { r ' ' o { { y \
p ' ' b { { g ' ' < .
{ < / " & ~ " & ~ " & <
_ . > / { . \ . . . . . ~
. . & . > } < . . _ . . . =
. > \ < = . . } . | > ' % < }
| \ . . _ \ . . > . . . . \ . }
. > < . | \ { { * < . > , < . > /
. \ } / . > . . . \ ' / . . / = = .
| . . . . | . / " . < _ > ) { { < \ .
. . . . _ > \ ' = . | . . . . . > {
> ) < . _ \ . . . . < . . \ . . =
. . _ / } \ ~ > < . | . . . . .
> e ' ' \ . < . } \ { { \ | .
/ < . . / e ; * \ . @ = _ .
~ > < . > { } < > < ; . (
~ . _ _ . . > \ . _ . .
> ' " n { { < > { < .
. . = " < . > . . /
Wyjaśnienie
Nie będę nawet próbował wyjaśniać wszystkich zawiłych ścieżek wykonania w tej wersji golfowej, ale algorytm i ogólny przepływ sterowania są identyczne z tą wersją bez golfa, która może być łatwiejsza do nauki dla naprawdę ciekawych po wyjaśnieniu algorytmu:
) { r ' ' o { { \ / ' ' p { . . .
. . . . . . . . y . b . . . . . . .
. . . . . . . . ' . . { . . . . . . .
. . . . . . . . \ ' g { / . . . . . . .
. . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . > . . . . < . . . . . . . . .
. . . . . . . . . . . . . . > . . ) < . . . . .
. . . . . . . . . . / = { { < . . . . ( . . . . .
. . . . . . . . . . . ; . . . > . . . . . . . . . <
. . . . . . . . . . . . > < . / e ; * \ . . . . . . .
. . . . . . . . . . . . @ . } . > { } < . . | . . . . .
. . . . . / } \ . . . . . . . > < . . . > { < . . . . . .
. . . . . . > < . . . . . . . . . . . . . . . | . . . . . .
. . . . . . . . _ . . > . . \ \ " ' / . . . . . . . . . . . .
. . . . . . \ { { \ . . . > < . . > . . . . \ . . . . . . . . .
. < . . . . . . . * . . . { . > { } n = { { < . . . / { . \ . . |
. > { { ) < . . ' . . . { . \ ' < . . . . . _ . . . > } < . . .
| . . . . > , < . . . e . . . . . . . . . . . . . = . . } . .
. . . . . . . > ' % < . . . . . . . . . . . . . & . . . | .
. . . . _ . . } . . > } } = ~ & " ~ & " ~ & " < . . . . .
. . . \ . . < . . . . . . . . . . . . . . . . } . . . .
. \ . . . . . . . . . . . . . . . . . . . . . . . < .
. . . . | . . . . . . . . . . . . . . . . . . = . .
. . . . . . \ . . . . . . . . . . . . . . . . / .
. . . . . . > . . . . . . . . . . . . . . . . <
. . . . . . . . . . . . . . . . . . . . . . .
_ . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
Szczerze mówiąc, w pierwszym akapicie żartowałem tylko w połowie. Fakt, że mamy do czynienia z cyklem sześciu elementów, był naprawdę wielką pomocą. Model pamięci Hexagony jest nieskończoną heksagonalną siatką, w której każda krawędź siatki zawiera liczbę całkowitą o dowolnej dokładności, zinicjalizowaną do zera.
Oto schemat układu pamięci, której użyłem w tym programie:
Długi prosty bit po lewej stronie jest używany jako ciąg zakończony 0 a
o dowolnym rozmiarze, który jest powiązany z literą r . Linie przerywane na innych literach reprezentują ten sam rodzaj struktury, każda obrócona o 60 stopni. Początkowo wskaźnik pamięci wskazuje krawędź oznaczoną 1 , zwróconą na północ.
Pierwszy, liniowy bit kodu ustawia wewnętrzną „gwiazdę” krawędzi na litery, roygbp
a także ustawia początkową krawędź na 1
, tak abyśmy wiedzieli, gdzie cykl się kończy / zaczyna (pomiędzy p
i r
):
){r''o{{y''g{{b''p{
Następnie wracamy do krawędzi oznaczonej jako 1 .
Ogólna idea algorytmu jest następująca:
- Dla każdej litery w cyklu czytaj dalej litery STDIN i, jeśli różnią się one od bieżącej litery, dołącz je do ciągu związanego z tą literą.
- Kiedy czytamy list, którego obecnie szukamy, przechowujemy
e
na brzegu etykietę ? , ponieważ dopóki cykl się nie zakończy, musimy założyć, że będziemy musieli także zjeść tę postać. Następnie przejdziemy przez pierścień do następnej postaci w cyklu.
- Proces ten można przerwać na dwa sposoby:
- Albo zakończyliśmy cykl. W takim przypadku wykonujemy kolejną szybką rundę w cyklu, zastępując wszystkie te
e
z pola ? krawędzie z n
s, ponieważ teraz chcemy, aby ten cykl pozostał na naszyjniku. Następnie przechodzimy do drukowania kodu.
- Lub trafiamy EOF (który rozpoznajemy jako kod znaku ujemnego). W takim przypadku zapisujemy wartość ujemną w ? krawędź obecnego znaku (dzięki czemu możemy łatwo odróżnić go od obu
e
i n
). Następnie szukamy 1 krawędzi (aby pominąć pozostałą część potencjalnie niepełnego cyklu) przed przejściem do drukowania kodu.
- Kod drukujący przechodzi ponownie przez cykl: dla każdego znaku w cyklu usuwa zapisany ciąg podczas drukowania
e
dla każdego znaku. Następnie przenosi się do ? krawędź związana z postacią. Jeśli jest ujemny, po prostu kończymy program. Jeśli jest pozytywny, po prostu go drukujemy i przechodzimy do następnej postaci. Po zakończeniu cyklu wracamy do kroku 2.
Inną rzeczą, która może być interesująca, jest to, jak zaimplementowałem łańcuchy o dowolnym rozmiarze (ponieważ po raz pierwszy użyłem nieograniczonej pamięci w Hexagony).
Wyobraźmy sobie, że jesteśmy w pewnym momencie, dokąd jeszcze czyta znaki dla R (tak, możemy użyć schemat jak jest) i A [0] i 1 zostały już wypełnione znaków (wszystko na północny-zachód z nich jest nadal zerem ). Np. Może właśnie przeczytaliśmy pierwsze dwa znaki wejścia do tych krawędzi i teraz czytamy a .og
y
Nowy znak jest odczytywany w na krawędzi. Używamy ? krawędzi, aby sprawdzić, czy ten znak jest równy r
. (Jest tu sprytna sztuczka: sześciokąt może łatwo rozróżniać między dodatnim i dodatnim, więc sprawdzanie równości poprzez odejmowanie jest denerwujące i wymaga co najmniej dwóch gałęzi. Ale wszystkie litery są mniejsze niż współczynnik 2, więc możemy porównać wartości, biorąc modulo, który da zero tylko wtedy, gdy będą równe.)
Ponieważ y
różni się od r
, przechodzimy do (nie znakowanych) od lewej krawędzi w i skopiować y
tam. Przechodzimy teraz bliższe okolice sześciokąta, kopiując znak jedną krawędź dodatkowo za każdym razem, dopóki mamy y
na przeciwległej krawędzi w . Ale teraz w [0] jest już postać, której nie chcemy zastępować. Zamiast tego, „drag” THE y
wokół następnego sześciokąta i sprawdzić się 1 . Ale jest tam też postać, więc idziemy o kolejny sześciokąt dalej. Teraz [2] wciąż wynosi zero, więc kopiujemyy
w tym. Wskaźnik pamięci przesuwa się teraz wzdłuż sznurka w kierunku pierścienia wewnętrznego. Wiemy, kiedy osiągnęliśmy początek łańcucha, ponieważ (nieznakowane) krawędzie między a [i] są zerowe, podczas gdy ? jest pozytywny.
Prawdopodobnie będzie to przydatna technika do pisania nietrywialnego kodu w Hexagony w ogóle.