Fueue , 423 bajty
Fueue to esolang oparty na kolejce, w którym działającym programem jest kolejka.
)$$4255%%1(~):[)$$24%%0:<[~:)~)]~[$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]](H-):~:[)[):~[)~:~~([:~)*[):~[$1(+48]):~+]-:~~)10)~~]/]+:5):]~:](106328966328112328136317639696111819119696281563139628116326221310190661962811611211962861109696289611619628116111612896281115421063633063961111116163963011632811111819159628151213262722151522061361613096119619190661966311961128966130281807072220060611612811961019070723232022060611
Wypróbuj online!
Jak to działa
To wyjaśnienie mogło wymknąć się spod kontroli. Z drugiej strony nie wiem, jak wyjaśnić to znacznie krócej, w sposób, w jaki mam nadzieję, że ludzie będą w stanie to zrobić.
Ściągawka Fueue
Zobacz artykuł wiki esolang, aby uzyskać szczegółowe informacje, w tym kilka funkcji nieużywanych w tym programie.
Program początkowy to stan początkowy kolejki, który może zawierać następujące elementy:
- Literały całkowite (tylko w źródle tylko nieujemne, ale ujemne można obliczyć), wykonanie ich powoduje wydrukowanie znaku.
- Bloki zagnieżdżone rozdzielone nawiasami kwadratowymi, obojętne (zachowane nienaruszone, chyba że zadziała na nie jakaś funkcja).
- Funkcje, ich argumenty to następujące po nich elementy w kolejce:
+*/-%
: arytmetyka liczb całkowitych ( -
jest jednostkowa,%
logiczna negacja). Obojętne, jeśli nie podano argumentów liczbowych.
()<
: wstaw element w nawiasach, usuń nawiasy z bloku, dodaj ostatni element do bloku. Dwa ostatnie są obojętne, chyba że następuje po nich blok.
~:
: zamiana, duplikat.
$
: kopia (pobiera liczbę + element). Obojętny przed nieliczbowym
H
: zatrzymanie programu.
Zauważ, że podczas []
zagnieżdżania, ()
nie - te ostatnie są po prostu osobnymi funkcjami.
Składnia śledzenia wykonania
Białe znaki są opcjonalne w Fueue, z wyjątkiem cyfr. W poniższych śladach wykonania zostanie on użyty do zasugerowania struktury programu, w szczególności:
- Kiedy funkcja się uruchomi, ona i jej argumenty zostaną wyłączone z otaczających elementów spacjami. Jeśli niektóre argumenty są skomplikowane, może być między nimi spacja.
- Wiele śladów wykonania jest podzielonych na „blok opóźniający” po lewej stronie, oddzielony od części po prawej, która wykonuje znaczną manipulację danymi. Zobacz następną sekcję.
Nawiasy klamrowe {}
(nieużywane w Fueue) są używane w śladach do reprezentowania wyniku liczb całkowitych wyrażeń matematycznych. Obejmuje to liczby ujemne, ponieważ Fueue ma tylko nieujemne literały - -
jest funkcją negacji.
Różne nazwy meta-zmiennych i ...
służą do oznaczania wartości i skrótów.
Opóźnianie taktyki
Intuicyjnie wykonywanie odbywa się cyklicznie wokół kolejki, częściowo modyfikując to, przez co przechodzi. Wyniki funkcji nie mogą być ponownie wykorzystane do następnego cyklu. Różne części programu ewoluują równolegle, o ile nie wchodzą w interakcje.
W rezultacie znaczna część kodu jest poświęcona synchronizacji, w szczególności opóźnieniu wykonania części programu do właściwego czasu. Istnieje wiele opcji gry w golfa, która ma tendencję do przekształcania tych części w nieczytelne obiekty BLOB, które można zrozumieć, śledząc ich wykonanie cykl po cyklu.
Te taktyki nie zawsze będą indywidualnie wymienione poniżej:
)[A]
opóźnienia A
dla cyklu. (Prawdopodobnie najłatwiejsza i najbardziej czytelna metoda).
~ef
zamienia elementy e
i f
który opóźnia również ich wykonanie. (Prawdopodobnie najmniej czytelny, ale często najkrótszy w przypadku drobnych opóźnień).
$1e
opóźnia pojedynczy element e
.
-
i %
są przydatne do opóźniania numerów (te ostatnie dla 0
i 1
.)
- Opóźniając kilka równych elementów pod rząd,
:
lub $
można je wykorzystać do utworzenia ich z jednego.
(n
owija się n
w nawiasy, które można później wygodnie usunąć. Jest to szczególnie istotne w przypadku obliczeń numerycznych, ponieważ liczby są zbyt niestabilne, aby można je nawet skopiować bez uprzedniego umieszczenia ich w bloku.
Ogólna struktura
Pozostałe objaśnienia są podzielone na siedem części, z których każda dotyczy części działającego programu. Większe cykle, po których większość się powtarza, będą nazywane „iteracjami”, aby odróżnić je od „cykli” pojedynczych przejść przez całą kolejkę.
Oto jak dzieli się między nimi program początkowy:
A: )$$4255%%1(~
B: ):[)$$24%%0:<[~:)~)]~[$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]]
C:
D: (H-
E:
F:
G: ):~:[)[):~[)~:~~([:~)*[):~[$1(+48]):~+]-:~~)10)~~]/]+:5):]~:](106328966328112328136317639696111819119696281563139628116326221310190661962811611211962861109696289611619628116111612896281115421063633063961111116163963011632811111819159628151213262722151522061361613096119619190661966311961128966130281807072220060611612811961019070723232022060611
Duża cyfra na końcu programu koduje resztę w odwrotnej kolejności, dwie cyfry na znak, z 30 odejmowanymi od każdej wartości ASCII (np. 10
Koduje a (
.)
Na wyższym poziomie możesz myśleć o danych w tym programie (zaczynając od bignum) jako przepływających od prawej do lewej, ale kontrolujących przepływających od lewej do prawej. Jednak na niższym poziomie Fueue cały czas zamazuje rozróżnienie między kodem a danymi.
- Sekcja G dekoduje bignum na cyfry ASCII (np. Cyfra
0
jako liczba całkowita 48
), najpierw dzieląc najmniej znaczące cyfry. Wytwarza jedną cyfrę co 15 cykli.
- Sekcja F zawiera wygenerowane cyfry wartości ASCII (każda wewnątrz bloku), dopóki sekcja E nie będzie mogła ich wykorzystać.
- Sekcja E obsługuje wytworzone cyfry po dwie na raz, łącząc je w bloki formularza
[x[y]]
, a także drukując zakodowany znak każdej pary.
- Sekcja D składa się z głęboko zagnieżdżonego bloku zbudowanego stopniowo z
[x[y]]
bloków w taki sposób, że gdy zawiera wszystkie cyfry, można go uruchomić, aby wydrukować wszystkie z nich, a następnie zatrzymać cały program.
- Sekcja C obsługuje budowę sekcji D, a także odtwarza sekcję E.
- Sekcja B odtwarza sekcję C oraz samą siebie co 30 cykli.
- Sekcja A odlicza cykle do ostatniej iteracji pozostałych sekcji. Następnie przerywa sekcję B i uruchamia sekcję D.
Sekcja A
Sekcja A zajmuje się planowaniem końca programu. Zmniejszenie do pojedynczej funkcji wymiany zajmuje 4258 cykli ~
, a następnie dostosowuje odcinek B, który zatrzymuje jego główną pętlę i zamiast tego uruchamia odcinek D.
)$ $4255% %1 (~
)$%%%...%% %0 [~]
)$%%%...% %1 [~]
⋮
)$ %0 [~]
) $1[~]
)[~]
~
$
Funkcja tworzy 4255 kopie następujących %
natomiast (
owija ~
w nawiasach.
- Każdy cykl
%
służy do przełączania następującej liczby między 0
i 1
.
- Gdy wszystkie
%
s zostaną zużyte, $1
tworzona jest 1 kopia [~]
(efektywnie NOP), aw następnym cyklu )
usuwa nawiasy.
Sekcja B
Sekcja B zajmuje się regeneracją, a także nową iteracją sekcji C co 30 cykli.
) : [)$$24%%0:<[~:)~)]~[$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]]
) [)$$24%%0:<[~:)~)]~[$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]] [BkB]
)$ $24% %0 :< [~:)~)] ~ [$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<] [BkB]
)$ %...%%% %1 < < [~:)~)] [BkB] [$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]
)$ %...%% %0 < [~:)~)[BkB]] [$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]
)$ %...% %1 [~:)~)[BkB][$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]]
⋮
) $1 [~:)~)[BkB][$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]]
) [~:)~)[BkB][$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]] (1)
~:) ~)[BkB] [$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]
) : [BkB] ) [$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<] (2)
) [BkB] [BkB] $11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<
- A
:
duplikuje następujący duży blok (jedna kopia w skrócie [BkB]
), a następnie )
usuwa nawiasy kwadratowe z pierwszej kopii.
$$24%%0
ustawia odliczanie podobne do tego w sekcji A.
- Podczas gdy to się odlicza,
:<
zamienia się <<
i ~
zamienia dwa bloki, umieszczając kod nowej sekcji C. na końcu.
- Dwie
<
funkcje pakują dwa ostatnie bloki do pierwszego - jest to zbędne w normalnych iteracjach, ale pozwoli na ~
wykonanie zadania z sekcji A na końcu.
- (1) Po zakończeniu odliczania
)
usuwa zewnętrzne nawiasy. Następnie ~:)
zamienia się w ):
i ~)
zamienia a )
na początek kodu sekcji C.
- (2) Sekcja B powraca teraz do początkowego cyklu, podczas gdy a
)
właśnie usuwa nawiasy klamrowe, aby rozpocząć nową iterację sekcji C.
W końcowej iteracji ~
sekcja A pojawia się w punkcie (1) powyżej:
~ ) [~:)~)[BkB][$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]] (1)
[~:)~)[BkB][$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]] )
W ~
zamienia )
na bloku i do sekcji C, zapobiegając sekcja B przed uruchomić ponownie.
Sekcja C
Sekcja C obsługuje scalanie nowych par cyfr w bloku sekcji D, a także tworzenie nowych iteracji sekcji E.
Poniżej pokazano typową iterację x
i y
reprezentację kodów ASCII cyfr. W pierwszej iteracji przychodzące elementy „D” i „E” są początkowe [H]
i -
zamiast tego, ponieważ żadna poprzednia sekcja E nie uruchomiła się, aby utworzyć pary cyfr.
C D E
$11~ ) ~<[[+$4--498+*-:~-10)):])<~] [)))~] < [)))~[...]] [x[y]]
~~~ ~~~ ~~~ ~~) [[+$4--498+*-:~-10)):])<~] < [)))~] [)))~[...][x[y]]]
~~~ ~~~ ) ~ [[+$4--498+*-:~-10)):])<~] [)))~[)))~[...][x[y]]]]
~~~ ~ ) [)))~[....]] [[+$4--498+*-:~-10)):])<~]
~~[)))~[....]] )[[+$4--498+*-:~-10)):])<~]
[)))~[....]] ~[+$4--498+*-:~-10)):])<~
- Używa innej metody synchronizacji, którą odkryłem dla tej odpowiedzi. Gdy masz kilka funkcji zamiany
~
w jednym rzędzie, rząd zmniejsza się do około 2/3 każdego cyklu (ponieważ jeden ~
zamienia dwa kolejne), ale czasami z resztą ~
s, która siejąc spustoszenie, ostrożnie manipuluje następującymi.
$11~
produkuje taki rząd. Następny ~
zamienia a <
w następnym bloku. Inny <
na końcu dołącza nowy blok par cyfr (cyfry xiy jako kody ASCII) do bloku sekcji D.
- W następnym cyklu
~
wiersz ma ~~
resztę, która zamienia a ~
na następną )
. Druga <
dołącza sekcję D do [)))~]
bloku.
- Następnie
~
sama zamiana zamienia następujący blok z nowym kodem sekcji E w bloku sekcji D. Następnie nowa resztka ~
zamienia krzyż )
, a na koniec ostatni ~~
z ~
rzędu zamienia jeden z nich na odcinek E, gdy tylko )
usunął nawiasy.
W końcowej iteracji sekcja A ~
zamieniła )
przekrój przez sekcję B i na sekcję C. Jednak sekcja C jest tak krótkotrwała, że już zniknęła, a )
kończy się na początku sekcji D.
Sekcja D
Sekcja D zajmuje się wydrukowaniem ostatniej dużej cyfry i zatrzymaniem programu. Przez większość przebiegu programu jest to obojętny blok, w którym sekcje B – G współpracują przy budowie.
(H -
[H]-
⋮
[)))~[H-]] After one iteration of section C
⋮
[)))~[)))~[H-][49[49]]]] Second iteration, after E has also run
⋮
) [)))~[...]] [49[48]] Final printing starts as ) is swapped in
))) ~[...][49[48]]
)) )[49[48]] [...]
)) 49 [48][...] Print first 1
) )[48] [...]
) 48 [...] Print 0
)[...] Recurse to inner block
...
⋮
)[H-] Innermost block reached
H - Program halts
- W pierwszym cyklu programu
(
funkcja nawijania otacza H
nawiasy. -
Poniżej, będzie stosowany jako obojętne element pierwszej iteracji zamiast cyfr pary.
- Włączona jest pierwsza para cyfr rzeczywistych
[49[49]]
, odpowiadająca końcowej 11
cyfrze.
- Bardzo ostatnia cyfra pary
[49[48]]
(odpowiadający 10
na początku liczebnika) w rzeczywistości nie jest włączona do bloku, ale to nie ma znaczenia, jak )[A[B]]
i )[A][B]
odpowiadają zarówno zmienia się A[B]
.
Po ostatniej iteracji następuje )
zamiana w prawo z sekcji B i blok sekcji D zostaje odblokowany. Na )))~
początku każdego podbloku upewnia się, że wszystkie części są wykonywane we właściwej kolejności. Wreszcie najbardziej wewnętrzny blok zawiera H
zatrzymanie programu.
Sekcja E
Sekcja E obsługuje łączenie par cyfr ASCII wytworzonych przez sekcję G i obie drukują odpowiedni zakodowany znak i wysyła blok z połączoną parą w lewo do sekcji C i D.
Ponownie poniżej pokazano typową iterację x
i y
reprezentację kodów ASCII cyfr.
E F
~ [+$4--498+*-:~-10)):] ) < ~ [y] [x]
) [+$4--498+*-:~-10)):] < [x] [y]
+ $4- - 498 +*- :~ -10 ) ) : [x[y]]
+--- -{-498} +*- ~~{-10} ) ) [x[y]] [x[y]]
+-- - 498 +* -{-10} ~ ) x [y] [x[y]]
+- -{-498} + * 10 x )[y] [x[y]]
+ - 498 + {10*x} y [x[y]]
+ {-498} {10*x+y} [x[y]]
{10*x+y-498} [x[y]]
[x[y]]
- Przychodzące bloki cyfr są zamieniane, następnie blok y jest dołączany do bloku x, a cały blok pary jest kopiowany. Jedna kopia pozostanie do końca dla sekcji C i D.
- Druga kopia jest ponownie odblokowana, a następnie do obliczenia stosowana jest sekwencja funkcji arytmetycznych
10*x+y-498
, wartość ASCII zakodowanego znaku. 498 = 10*48+48-30
, 48
s cofnie kodowanie ASCII x
i y
podczas gdy 30
przesuwa kodowanie z 00–99
na 30–129
, co obejmuje wszystkie drukowalne ASCII.
- Wynikowy numer jest następnie pozostawiony do wykonania, co wypisuje jego znak.
Sekcja F.
Sekcja F składa się z obojętnych bloków zawierających kody cyfr ASCII. W przypadku większości uruchomionych programów będą tu maksymalnie dwa, ponieważ sekcja E zużywa je z tą samą prędkością, z jaką wytwarza je G. Jednak w końcowej fazie drukowania 0
zostaną tutaj zebrane zbędne cyfry.
[y] [x] ...
Sekcja G
Sekcja G obsługuje dzielenie dużej liczby na końcu programu, najpierw najmniej znaczących cyfr, i wysyłanie bloków z kodami ASCII w lewo do innych sekcji.
Ponieważ nie ma kontroli zatrzymania, w rzeczywistości będzie kontynuował generowanie 0
cyfr, gdy liczba zmniejszy się do 0, dopóki sekcja D nie zatrzyma całego programu z H
funkcją.
[BkG]
skraca kopię dużego bloku kodu początkowego, który służy do samoreplikacji w celu rozpoczęcia nowych iteracji.
Inicjalizacja w pierwszych cyklach:
) :~ : [)[):~[)~:~~([:~)*[):~[$1(+48]):~+]-:~~)10)~~]/]+:5):]~:] ( 106328966328112328136317639696111819119696281563139628116326221310190661962811611211962861109696289611619628116111612896281115421063633063961111116163963011632811111819159628151213262722151522061361613096119619190661966311961128966130281807072220060611612811961019070723232022060611
) ~ ~ [)[):~[)~:~~([:~)*[):~[$1(+48]):~+]-:~~)10)~~]/]+:5):]~:] [BkG] [10...11]
) [)[):~[)~:~~([:~)*[):~[$1(+48]):~+]-:~~)10)~~]/]+:5):]~:] ~ [BkG] [10...11]
) [):~[)~:~~([:~)*[):~[$1(+48]):~+]-:~~)10)~~]/]+:5):] ~ : [10...11] [BkG]
Typowa iteracja N
oznacza liczbę do podzielenia:
) [):~[)~:~~([:~)*[):~[$1(+48]):~+]-:~~)10)~~]/]+:5):] ~ : [N] [BkG]
) :~ [)~:~~([:~)*[):~[$1(+48]):~+]-:~~)10)~~]/]+ :5 ) : [N] : [BkG]
) ~ ~ [)~:~~([:~)*[):~[$1(+48]):~+]-:~~)10)~~]/] +5 5 ) [N] [N] [BkG] [BkG]
) [)~:~~([:~)*[):~[$1(+48]):~+]-:~~)10)~~]/] ~ 10 N [N] [BkG] [BkG]
) ~:~ ~ ( [:~)*[):~[$1(+48]):~+]-:~~)10)~~] / N 10 [N] [BkG] [BkG]
) ~ : [:~)*[):~[$1(+48]):~+]-:~~)10)~~] ( {N/10} [N] [BkG] [BkG]
) [:~)*[):~[$1(+48]):~+]-:~~)10)~~] : [{N/10}] [N] [BkG] [BkG]
:~ )*[):~[$1(+48]):~+]- :~ ~)10 ) ~ ~ [{N/10}] [{N/10}] [N] [BkG] [BkG]
~~) *[):~[$1(+48]):~+]- ~~10 ) ) [{N/10}] ~ [{N/10}] [N] [BkG] [BkG]
) ~ * [):~[$1(+48]):~+] -10 ~ ) {N/10} [N] [{N/10}] [BkG] [BkG]
) [):~[$1(+48]):~+] * {-10} {N/10} ) [N] [{N/10}] [BkG] [BkG]
) :~ [$1(+48]) :~ + {-10*(N/10)} N [{N/10}] [BkG] [BkG]
) ~ ~ [$1(+48] ) ~ ~ {N%10} [{N/10}] [BkG] [BkG]
) [$1(+48] ~ ) {N%10} ~ [{N/10}] [BkG] [BkG]
$1( + 48 {N%10} ) [BkG] [{N/10}] [BkG]
( {48+N%10} BkG [{N/10}] [BkG] New iteration starts
[{48+N%10}] ....
- Kropla opóźniająca jest tutaj szczególnie owłosiona. Jednak jedyną nową sztuczką opóźniającą jest użycie
+:5
zamiast --10
opóźnienia 10
dwóch cykli. Niestety 10
pomógł tylko jeden z programów.
[N]
I [BkG]
bloki są powielane, a następnie jeden egzemplarz N
jest podzielona 10
.
[{N/10}]
jest duplikowane, wówczas do obliczenia kodu ASCII ostatniej cyfry N
as stosuje się więcej funkcji arytmetycznych 48+((-10)*(N/10)+N)
. Blok z tym kodem ASCII pozostawia się w sekcji F.
- Druga kopia
[{N/10}]
zostaje zamieniona między [BkG]
blokami, aby ustawić początek nowej iteracji.
Quine bonusowa (540 bajtów)
)$$3371%%1[~!~~!)!]):[)$$20%%0[):]~)~~[)$$12%%0[<$$7%~~0):~[+----48+*-~~10))]<]<~!:~)~~[40~[:~))~:~[)~(~~/[+--48):]~10]+30])):]]][)[H]](11(06(06(21(21(25(19(07(07(19(61(96(03(96(96(03(11(03(63(11(28(61(11(06(06(20(18(07(07(18(61(11(28(63(96(11(96(96(61(11(06(06(19(20(07(07(18(61(30(06(06(25(07(96(96(18(11(28(96(61(13(15(15(15(15(22(26(13(12(15(96(96(19(18(11(11(63(30(63(30(96(03(28(96(11(96(96(61(22(18(96(61(28(96(11(11(96(28(96(61(11(96(10(96(96(17(61(13(15(15(22(26(11(28(63(96(19(18(63(13(21(18(63(11(11(28(63(63(63(61(11(61(42(63(63
Wypróbuj online!
Ponieważ nie byłem pewien, która metoda będzie najkrótsza, najpierw spróbowałem zakodować znaki jako liczby dwucyfrowe oddzielone (
s. Kod podstawowy jest nieco krótszy, ale rekompensuje to 50% większa reprezentacja danych. Nie tak golfowy jak ten drugi, ponieważ zatrzymałem się, kiedy zdałem sobie sprawę, że to nie przebije. Ma jedną zaletę: nie wymaga implementacji z obsługą bignum.
Jego ogólna struktura jest nieco podobna do głównej. Brak sekcji G, ponieważ reprezentacja danych wypełnia bezpośrednio sekcję F. Jednak sekcja E musi wykonać podobne obliczenia divmod, aby zrekonstruować cyfry liczb dwucyfrowych.