2.}<@>%?<{>$"/\M!8;
Czytelny:
2 . }
< @ > %
? < { > $
" / \ M
! 8 ;
Wypróbuj online!
Prawdopodobnie można go zagrać w bajt lub dwa bajty, ale może to wymagać naprawdę pomysłowego układu, który można łatwiej znaleźć za pomocą brutalnej siły (nawet jeśli znalezienie go może potrwać dość długo).
Wyjaśnienie na wysokim poziomie
Program przeważnie stosuje ten pseudokod:
while (read number is not zero)
{
if (number is even)
print number;
}
Które nadużywają sposobu, w jaki Hexagony próbuje odczytać liczbę, gdy STDIN jest pusty (zwraca zero). Ogromne podziękowania dla Martina za pomoc w opracowaniu tego podejścia.
Pełne wyjaśnienie
Nadal nie majstrowałem przy Mono, żeby zdobyć Timwi fantastyczne ezoteryczne IDE , więc zaufałem Martinowi, aby dostarczył mi kilka pomocnych ładnych zdjęć!
Najpierw mały podkład na podstawowy przepływ kontrolny w Hexagony. Pierwszy wskaźnik instrukcji (IP), który jest jedynym używanym w tym programie, zaczyna się w lewym górnym rogu heksagonalnego kodu źródłowego i zaczyna przesuwać się w prawo. Ilekroć IP opuszcza krawędź sześciokąta, porusza sięside_length - 1
rzędy w kierunku środka sześciokąta. Ponieważ ten program używa sześciokąta o długości boku trzy, adres IP zawsze będzie się przesuwał o dwa rzędy, kiedy to nastąpi. Jedynym wyjątkiem jest sytuacja, gdy odsuwa się od środkowego rzędu, gdzie warunkowo przesuwa się w kierunku góry lub dołu sześciokąta, w zależności od wartości aktualnej krawędzi pamięci.
Teraz trochę o warunkach. Jedynymi warunkami w Hexagony dla przepływu kontrolnego są >
:<
a środkowa krawędź sześciokąta. Wszystkie one działają zgodnie ze stałą zasadą: jeśli wartość na bieżącym zboczu pamięci wynosi zero lub ujemny przepływ sterowania przesuwa się w lewo, a jeśli jest dodatni, sterowanie płynie w prawo. Większe niż i mniejsze niż nawiasy przekierowują IP pod kątem sześćdziesięciu stopni, podczas gdy krawędź sześciokąta określa, do którego rzędu skacze IP.
Heksagonia ma również specjalny model pamięci, w którym wszystkie dane są przechowywane na krawędziach nieskończonej sześciokątnej siatki. Ten program używa tylko trzech krawędzi: jednej do przechowywania dwóch, jednej dla aktualnie odczytywanego numeru i jednej dla liczby dwóch modułów. Wygląda mniej więcej tak:
Mod \ / Input
|
2
Nie zamierzam dokładnie wyjaśniać, gdzie jesteśmy w pamięci w każdym punkcie podczas wyjaśniania programu, więc wróć tutaj, jeśli się zdezorientujesz, gdzie jesteśmy w pamięci.
Po tym wszystkim, prawdziwe wyjaśnienie może się rozpocząć. Najpierw wypełniamy krawędź „2” pamięcią 2, a następnie wykonujemy brak operacji i przesuwamy wskaźnik pamięci w prawo ( 2.}
).
Następnie rozpoczynamy główną pętlę programu. Czytamy pierwszy numer ze STDIN, a następnie trafiamy na warunkowy ( ?<
). Jeśli w STDIN nie ma żadnych liczb, to odczytuje zero w bieżącym zboczu pamięci, więc skręcamy w lewo na @
, co kończy program. W przeciwnym razie odbijamy się od lustra, przesuwamy wskaźnik pamięci do tyłu i w lewo, owijamy sześciokąt, aby obliczyć pozostałą część dzielenia danych wejściowych przez 2, a następnie uderzamy w inną funkcję warunkową ( /"%>
).
Jeśli reszta to jeden (tzn. Liczba była nieparzysta), skręcamy w prawo, podążając niebieską ścieżką powyżej, zaczynając od ponownego wykonania operacji no-op, a następnie zawijamy się do dolnej części sześciokąta, mnożymy bieżącą krawędź przez 10, a następnie dodajemy ósemka, odbij się od kilku luster, wykonaj to samo mnożenie i dodawanie jeszcze raz, otrzymując 188 na bieżącej krawędzi, owijając się z powrotem na górę sześciokąta, ponownie wykonując brak operacji i na końcu kończąc program ( .8/\8.@
). Ten zawiły wynik był szczęśliwym wypadkiem, pierwotnie napisałem dużo prostszą logikę, ale zauważyłem, że mogę go usunąć na korzyść braku operacji, który, jak myślałem, był bardziej w duchu Sześciokąta.
Jeśli reszta to zero, skręcamy w lewo, podążając czerwoną ścieżką powyżej. Powoduje to przesunięcie wskaźnika pamięci w lewo, a następnie wydrukowanie tam wartości (wartości wejściowej) jako liczby. Zwierciadło, które napotykamy, działa jako brak działania ze względu na kierunek, w którym się poruszamy ( ). Ponieważ wartość 77 jest dodatnia, poruszamy się w kierunku dolnej części sześciokąta iz powodu trampoliny pomiń pierwszą instrukcję ( ). Następnie mnożymy bieżącą krawędź pamięci przez 10 i dodajemy 8, otrzymując 778. Następnie wyprowadzamy tę wartość mod 256 (10) jako znak ASCII, który okazuje się być nowym znakiem. Na koniec wychodzimy z sześciokąta i wracamy do pierwszej, która zastępuje 778 następną wartością wejściową.{/!
). Następnie uderzamy o krawędź sześciokąta, który działa warunkowo z tylko jednym wynikiem, ponieważ wcześniej wprowadzona wartość została już przetestowana pod kątem dodatniej, więc zawsze poruszamy się w prawo (jeśli wyobrażasz sobie, że patrzysz w kierunku IP) . Następnie mnożymy dane wejściowe przez 10 i dodajemy dwa, tylko w celu zmiany kierunku, zawinięcia i zastąpienia nowej wartości wartością ascii wielkiej litery M, 77. Następnie uderzamy w lustra i wychodzimy poza krawędź środka sześciokąt z trampoliną (2<M\>$
!
?