Fueue , 423 byte
Fueue adalah esolang berbasis antrian di mana program yang berjalan adalah antrian.
)$$4255%%1(~):[)$$24%%0:<[~:)~)]~[$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]](H-):~:[)[):~[)~:~~([:~)*[):~[$1(+48]):~+]-:~~)10)~~]/]+:5):]~:](106328966328112328136317639696111819119696281563139628116326221310190661962811611211962861109696289611619628116111612896281115421063633063961111116163963011632811111819159628151213262722151522061361613096119619190661966311961128966130281807072220060611612811961019070723232022060611
Cobalah online!
Bagaimana itu bekerja
Penjelasan ini mungkin atau mungkin tidak ada jalan keluar. Di sisi lain saya tidak tahu bagaimana menjelaskannya dengan lebih singkat dengan cara yang saya harap orang bisa ikuti.
Lembar cheat Fueue
Lihat artikel wiki esolang untuk detailnya, termasuk beberapa fitur yang tidak digunakan dalam program ini.
Program awal adalah keadaan awal antrian, yang dapat berisi elemen-elemen berikut:
- Bilangan bulat integer (hanya non-negatif dalam sumber, tetapi yang negatif dapat dihitung), mengeksekusi mereka mencetak karakter.
- Blok bersarang dibatasi braket kotak, lembam (dipertahankan utuh kecuali beberapa fungsi menindakinya).
- Fungsinya, argumen mereka adalah elemen yang mengikutinya segera dalam antrian:
+*/-%
: bilangan bulat aritmatika ( -
adalah unary, %
negasi logis). Lemah jika tidak diberi nomor argumen.
()<
: letakkan elemen dalam tanda kurung, hapus tanda kurung dari blok, tambahkan elemen terakhir ke blok. Dua yang terakhir inert kecuali diikuti oleh blok.
~:
: swap, duplikat.
$
: copy (mengambil nomor + elemen). Lambat sebelum non-angka.
H
: menghentikan program.
Perhatikan bahwa saat []
bersarang, ()
jangan - yang terakhir hanyalah fungsi yang terpisah.
Sintaks penelusuran jejak
Spasi adalah opsional dalam Fueue, kecuali antara angka. Dalam jejak eksekusi berikut ini akan digunakan untuk menyarankan struktur program, khususnya:
- Ketika suatu fungsi dijalankan, ia dan argumennya akan dimatikan dari elemen sekitarnya dengan spasi. Jika beberapa argumen rumit, mungkin ada ruang di antara mereka juga.
- Banyak jejak eksekusi dibagi menjadi "delay blob" di sebelah kiri, dipisahkan dari bagian di sebelah kanan yang melakukan manipulasi data yang substansial. Lihat bagian selanjutnya.
Kurung keriting {}
(tidak digunakan dalam Fueue) digunakan dalam jejak untuk mewakili hasil integer dari ekspresi matematika. Ini termasuk angka negatif, karena Fueue hanya memiliki literal non-negatif - -
adalah fungsi negasi.
Berbagai nama metavariabel dan ...
digunakan untuk menunjukkan nilai dan singkatan.
Taktik penundaan
Secara intuitif, siklus eksekusi di sekitar antrian, sebagian memodifikasi apa yang dilewatinya. Hasil dari suatu fungsi tidak dapat dijalankan lagi sampai siklus berikutnya. Bagian-bagian berbeda dari program secara efektif berkembang secara paralel selama mereka tidak berinteraksi.
Akibatnya, banyak kode yang ditujukan untuk sinkronisasi, khususnya untuk menunda eksekusi bagian-bagian program hingga waktu yang tepat. Ada banyak opsi untuk bermain golf ini, yang cenderung mengubah bagian-bagian itu menjadi gumpalan yang tidak dapat dibaca yang hanya dapat dipahami dengan melacak siklus eksekusi mereka dengan siklus.
Taktik ini tidak akan selalu disebutkan secara individual di bawah ini:
)[A]
keterlambatan A
untuk satu siklus. (Mungkin metode termudah dan paling mudah dibaca.)
~ef
menukar elemen e
dan f
yang juga menunda eksekusi. (Mungkin yang paling tidak mudah dibaca, tetapi sering kali paling pendek untuk penundaan kecil.)
$1e
menunda satu elemen e
.
-
dan %
berguna untuk menunda angka (yang terakhir untuk0
dan 1
.)
- Saat menunda beberapa elemen yang sama dalam satu baris,
:
atau $
dapat digunakan untuk membuatnya dari satu elemen .
(n
membungkus n
tanda kurung, yang nantinya dapat dihapus dengan nyaman. Ini sangat penting untuk perhitungan numerik, karena angka terlalu tidak stabil untuk disalin tanpa terlebih dahulu menempatkannya di blok.
Struktur keseluruhan
Sisa dari penjelasan ini dibagi menjadi tujuh bagian, masing-masing untuk bagian dari program yang sedang berjalan. Siklus yang lebih besar setelah sebagian besar dari mereka mengulangi sendiri akan disebut "iterasi" untuk membedakan mereka dari "siklus" melewati tunggal melalui seluruh antrian.
Berikut adalah bagaimana program awal dibagi di antara mereka:
A: )$$4255%%1(~
B: ):[)$$24%%0:<[~:)~)]~[$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]]
C:
D: (H-
E:
F:
G: ):~:[)[):~[)~:~~([:~)*[):~[$1(+48]):~+]-:~~)10)~~]/]+:5):]~:](106328966328112328136317639696111819119696281563139628116326221310190661962811611211962861109696289611619628116111612896281115421063633063961111116163963011632811111819159628151213262722151522061361613096119619190661966311961128966130281807072220060611612811961019070723232022060611
Angka besar pada akhir program mengkodekan sisanya secara terbalik, dua digit per karakter, dengan 30 dikurangkan dari setiap nilai ASCII (jadi mis. 10
Mengkode a (
.)
Pada level yang lebih tinggi, Anda dapat menganggap data dalam program ini (dimulai dengan bignum) sebagai mengalir dari kanan ke kiri, tetapi kontrol mengalir dari kiri ke kanan. Namun, pada level yang lebih rendah, Fueue membuat perbedaan antara kode dan data setiap saat.
- Bagian G menerjemahkan bignum menjadi angka ASCII (misalnya digit
0
sebagai bilangan bulat 48
), memisahkan angka yang paling tidak penting terlebih dahulu. Ini menghasilkan satu digit setiap 15 siklus.
- Bagian F berisi nilai ASCII digit yang dihasilkan (masing-masing di dalam blok) sampai bagian E dapat mengkonsumsinya.
- Bagian E menangani angka yang dihasilkan dua sekaligus, memasangkannya ke dalam blok formulir
[x[y]]
, juga mencetak karakter yang disandikan dari masing-masing pasangan.
- Bagian D terdiri dari blok yang sangat bersarang yang secara bertahap dibangun dari
[x[y]]
blok sedemikian rupa sehingga setelah berisi semua digit, dapat dijalankan untuk mencetak semuanya, lalu menghentikan seluruh program.
- Bagian C menangani konstruksi bagian D, dan juga membuat ulang bagian E.
- Bagian B menciptakan kembali bagian C serta dirinya sendiri setiap 30 siklus.
- Bagian A menghitung mundur siklus sampai iterasi terakhir dari bagian lain. Kemudian ia membatalkan bagian B dan menjalankan bagian D.
Bagian A
Bagian A menangani penjadwalan akhir program. Dibutuhkan 4258 siklus untuk mereduksi menjadi fungsi swap tunggal ~
, yang kemudian membuat penyesuaian ke bagian B yang menghentikan loop utamanya dan mulai menjalankan bagian D sebagai gantinya.
)$ $4255% %1 (~
)$%%%...%% %0 [~]
)$%%%...% %1 [~]
⋮
)$ %0 [~]
) $1[~]
)[~]
~
- Suatu
$
fungsi menciptakan 4255 salinan berikut ini %
sementara (
membungkus ~
tanda kurung.
- Setiap siklus yang terakhir
%
digunakan untuk beralih nomor berikut antara 0
dan 1
.
- Ketika semua
%
digunakan, $1
salinan 1 dibuat [~]
(efektif NOP), dan pada siklus berikutnya )
menghapus tanda kurung.
Bagian B
Bagian B menangani regenerasi sendiri serta pengulangan baru dari bagian C setiap 30 siklus.
) : [)$$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)):])<~][)))~]<
- Sebuah
:
duplikat mengikuti blok besar (satu salinan disingkat [BkB]
), lalu)
menghapus tanda kurung dari salinan pertama.
$$24%%0
membuat hitung mundur yang mirip dengan yang ada di bagian A.
- Sementara ini menghitung mundur,
:<
berubah menjadi <<
, dan ~
menukar dua blok, menempatkan kode untuk bagian C baru terakhir.
- Dua
<
fungsi mengemas dua blok terakhir ke yang pertama - ini berlebihan pada iterasi normal, tetapi akan memungkinkan ~
dari bagian A untuk melakukan tugasnya di akhir.
- (1) Ketika hitungan mundur selesai,
)
tanda kurung luar dihapus. Selanjutnya ~:)
berubah menjadi ):
dan ~)
menukar )
ke awal kode bagian C.
- (2) Bagian B sekarang kembali pada siklus awalnya, sementara a
)
baru saja akan menghapus tanda kurung untuk mulai menjalankan iterasi baru dari bagian C.
Dalam iterasi akhir, ~
dari bagian A muncul di titik (1) di atas:
~ ) [~:)~)[BkB][$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]] (1)
[~:)~)[BkB][$11~)~<[[+$4--498+*-:~-10)):])<~][)))~]<]] )
The ~
swap yang )
di blok dan ke bagian C, mencegah bagian B dari yang dijalankan lagi.
Bagian C
Bagian C menangani penggabungan pasangan karakter digit baru ke dalam blok bagian D, dan juga membuat iterasi baru dari bagian E.
Di bawah ini menunjukkan iterasi khas dengan x
dan y
mewakili kode ASCII digit. Dalam iterasi pertama, elemen "D" dan "E" yang masuk adalah yang pertama [H]
dan -
sebagai gantinya, karena tidak ada bagian E sebelumnya yang dijalankan untuk menghasilkan pasangan karakter digit apa pun.
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)):])<~
- Ini menggunakan metode sinkronisasi yang berbeda yang saya temukan untuk jawaban ini. Ketika Anda memiliki beberapa fungsi swap
~
berturut-turut, baris tersebut akan menyusut menjadi sekitar 2/3 setiap siklus (karena satu ~
swap dua berikut), tetapi kadang-kadang dengan sisa dari ~
s yang mendatangkan malapetaka memanipulasi dengan hati-hati apa yang mengikuti.
$11~
menghasilkan baris seperti itu. Selanjutnya ~
swap a <
di blok berikut. Lain <
di akhir menambahkan blok pasangan digit baru (digit x dan y sebagai kode ASCII) ke dalam blok bagian D.
- Siklus berikutnya,
~
baris memiliki ~~
sisa, yang bertukar ~
atas yang berikut ini )
. Yang lain <
menambahkan bagian D ke a[)))~]
blok.
- Selanjutnya swap
~
itu sendiri menukar blok berikut dengan kode E bagian baru di seluruh blok bagian D. Kemudian sisa baru ~
menukar )
seberang, dan akhirnya yang terakhir ~~
di ~
baris menukar salah satu dari mereka menyeberang ke bagian E sama seperti )
telah menghapus tanda kurung.
Dalam iterasi akhir, bagian A ~
telah bertukar )
melintasi bagian B dan ke bagian C. Namun, bagian C berumur pendek sehingga sudah menghilang, dan )
berakhir di awal bagian D.
Bagian D
Bagian D menangani pencetakan angka besar terakhir dan menghentikan program. Selama sebagian besar program dijalankan, itu adalah blok lembam yang bagian B – G bekerja sama dalam membangun.
(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
- Pada siklus pertama program,
(
membungkus fungsi penghentian H
dalam tanda kurung. SEBUAH-
berikut, itu akan digunakan sebagai elemen dummy untuk iterasi pertama, bukan pasangan digit.
- Pasangan digit nyata pertama yang digabungkan adalah
[49[49]]
, sesuai dengan final 11
dalam angka.
- Pasangan digit terakhir
[49[48]]
(sesuai dengan 10
di awal numeral) sebenarnya tidak dimasukkan ke dalam blok, tetapi ini tidak membuat perbedaan sama )[A[B]]
dan )[A][B]
setara, keduanya berubah menjadi A[B]
.
Setelah iterasi terakhir, yang )
ditukar ke kanan dari bagian B tiba dan bagian D blok diblokir. Di )))~
awal setiap sub-blok memastikan bahwa semua bagian dieksekusi dalam urutan yang benar. Akhirnya blok terdalam berisi H
penghentian program.
Bagian E
Bagian E menangani kombinasi pasangan digit ASCII yang diproduksi oleh bagian G, dan keduanya mencetak karakter yang dikodekan yang sesuai dan mengirimkan blok dengan pasangan gabungan ke kiri ke bagian C dan D.
Sekali lagi di bawah ini menunjukkan iterasi khas dengan x
dan y
mewakili kode ASCII digit.
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]]
- Blok digit yang masuk ditukar, kemudian blok y ditambahkan ke blok x, dan seluruh blok pasangan disalin. Satu salinan akan dibiarkan sampai akhir untuk bagian C dan D.
- Salinan lainnya di-deblock lagi, lalu urutan fungsi aritmatika diterapkan untuk menghitung
10*x+y-498
, nilai ASCII dari karakter yang dikodekan. 498 = 10*48+48-30
, 48
s membatalkan pengodean ASCII dari x
dan y
sementara 30
menggeser pengodean dari 00–99
ke30–129
, yang mencakup semua ASCII yang dapat dicetak.
- Angka yang dihasilkan kemudian dibiarkan dieksekusi, yang mencetak karakternya.
Bagian F
Bagian F terdiri dari blok inert yang berisi kode digit ASCII. Untuk sebagian besar program yang dijalankan akan ada paling banyak dua di sini, karena bagian E mengkonsumsinya dengan kecepatan yang sama dengan yang dihasilkan G. Namun, pada tahap pencetakan akhir, beberapa 0
angka berlebih akan dikumpulkan di sini.
[y] [x] ...
Bagian G
Bagian G menangani pemisahan angka besar di akhir program, angka paling tidak penting terlebih dahulu, dan mengirim blok dengan kode ASCII mereka ke kiri ke bagian lain.
Karena tidak ada cek penghentian, itu akan benar-benar terus menghasilkan 0
angka ketika angka telah dipangkas menjadi 0, sampai bagian D menghentikan seluruh program dengan H
fungsi.
[BkG]
menyingkat salinan blok kode awal yang besar, yang digunakan untuk replikasi diri untuk memulai iterasi baru.
Inisialisasi dalam siklus pertama:
) :~ : [)[):~[)~:~~([:~)*[):~[$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]
Iterasi tipikal, N
menunjukkan nomor yang akan dipisah:
) [):~[)~:~~([:~)*[):~[$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}] ....
- Gumpalan penundaan di sini sangat berbulu. Namun, satu-satunya trik penundaan baru adalah menggunakan
+:5
alih-alih --10
menunda 10
dua siklus. Sayangnya hanya satu dari 10
program yang dibantu oleh ini.
- The
[N]
dan [BkG]
blok digandakan, maka satu salinan N
dibagi oleh10
.
[{N/10}]
digandakan, maka lebih banyak fungsi aritmatika digunakan untuk menghitung kode ASCII dari digit terakhir N
as 48+((-10)*(N/10)+N)
. Blokir dengan kode ASCII ini dibiarkan untuk bagian F.
- Salinan lain
[{N/10}]
ditukar antara [BkG]
blok untuk mengatur awal iterasi baru.
Bonus quine (540 bytes)
)$$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
Cobalah online!
Karena saya tidak yakin metode mana yang akan terpendek, saya pertama kali mencoba menyandikan karakter sebagai angka dua digit yang dipisahkan oleh (
s. Kode inti sedikit lebih pendek, tetapi representasi data 50% lebih besar menggantikannya. Tidak golf seperti yang lain, ketika saya berhenti ketika saya menyadari itu tidak akan mengalahkan itu. Ini memiliki satu keuntungan: Tidak memerlukan implementasi dengan dukungan bignum.
Struktur keseluruhannya agak mirip dengan yang utama. Bagian G tidak ada karena representasi data mengisi bagian F secara langsung. Namun, bagian E harus melakukan perhitungan divmod yang sama untuk merekonstruksi digit angka dua digit.