Tidak dapat dibaca , 2199 2145 2134 2104 2087 2084 byte
Mendukung baik k
/ j
maupun ▲
/ ▼
sintaksis.
Dalam tradisi Unreadable yang baik, berikut adalah program yang diformat dalam font proporsional, untuk mengaburkan perbedaan antara tanda kutip dan tanda kutip ganda:
'"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "'"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""'"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "'"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """ "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "'"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""'"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """ "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """ "" "" "" "" ""
Ini adalah tantangan yang luar biasa. Terima kasih telah mengirim!
Penjelasan
Untuk memahami apa yang bisa dan tidak bisa dilakukan Unreadable, bayangkan Brainfuck dengan pita tak terbatas di kedua arah, tetapi alih-alih penunjuk memori yang memindahkan satu sel pada satu waktu, Anda dapat mengakses sel memori apa pun dengan mendereferensikan penunjuk. Ini sangat berguna dalam solusi ini, meskipun operasi aritmatika lainnya - termasuk modulo - harus dilakukan dengan tangan.
Berikut adalah program sebagai kodesemu dengan komentar sutradara:
// Initialize memory pointer. Why 5 will be explained at the very end!
ptr = 5
// FIRST PASS:
// Read all characters from stdin, store them in memory, and also keep track of the
// current line number at each character.
// We need the +1 here so that EOF, which is -1, ends the loop. We increment ptr by 2
// because we use two memory cells for each input character: one contains the actual
// character (which we store here); the other will contain the line number at which the
// character occurs (updated at the end of this loop body).
while ch = (*(ptr += 2) = read) + 1:
// At this point, ch will be one more than the actual value.
// However, the most code-economical way for the following loop is to
// decrement inside the while condition. This way we get one fewer
// iteration than the value of ch. Thus, the +1 comes in handy.
// We are now going to calculate modulo 4 and 5. Why? Because
// the mod 4 and 5 values of the desired input characters are:
//
// ch %5 %4
// ^ 1
// v 2
// k 3
// j 4
// ▲ 0 2
// ▼ 0 0
//
// As you can see, %5 allows us to differentiate all of them except ▲/▼,
// so we use %4 to differentiate between those two.
mod4 = 0 // read Update 2 to find out why mod5 = 0 is missing
while --ch:
mod5 = mod5 ? mod5 + 1 : -4
mod4 = mod4 ? mod4 + 1 : -3
// At the end of this loop, the value of mod5 is ch % 5, except that it
// uses negative numbers: -4 instead of 1, -3 instead of 2, etc. up to 0.
// Similarly, mod4 is ch % 4 with negative numbers.
// How many lines do we need to go up or down?
// We deliberately store a value 1 higher here, which serves two purposes.
// One, as already stated, while loops are shorter in code if the decrement
// happens inside the while condition. Secondly, the number 1 ('""") is
// much shorter than 0 ('""""""""'""").
up = (mod5 ? mod5+1 ? mod5+3 ? 1 : 3 : 2 : mod4 ? 3 : 1)
dn = (mod5 ? mod5+2 ? mod5+4 ? 1 : 3 : 2 : mod4 ? 1 : 3)
// As an aside, here’s the reason I made the modulos negative. The -1 instruction
// is much longer than the +1 instruction. In the above while loop, we only have
// two negative numbers (-3 and -4). If they were positive, then the conditions in
// the above ternaries, such as mod5+3, would have to be mod5-3 etc. instead. There
// are many more of those, so the code would be longer.
// Update the line numbers. The variables updated here are:
// curLine = current line number (initially 0)
// minLine = smallest linenum so far, relative to curLine (always non-positive)
// maxLine = highest linenum so far, relative to curLine (always non-negative)
// This way, we will know the vertical extent of our foray at the end.
while --up:
curLine--
minLine ? minLine++ : no-op
maxLine++
while --dn:
curLine++
minLine--
maxLine ? maxLine-- : no-op
// Store the current line number in memory, but +1 (for a later while loop)
*(ptr + 1) = curLine + 1
// At the end of this, minLine and maxLine are still relative to curLine.
// The real minimum line number is curLine + minLine.
// The real maximum line number is curLine + maxLine.
// The total number of lines to output is maxLine - minLine.
// Calculate the number of lines (into maxLine) and the real minimum
// line number (into curLine) in a single loop. Note that maxLine is
// now off by 1 because it started at 0 and thus the very line in which
// everything began was never counted.
while (++minLine) - 1:
curLine--
maxLine++
// Make all the row numbers in memory positive by adding curLine to all of them.
while (++curLine) - 1:
ptr2 = ptr + 1
while (ptr2 -= 2) - 2: // Why -2? Read until end!
*ptr2++
// Finally, output line by line. At each line, we go through the memory, output the
// characters whose the line number is 0, and decrement that line number. This way,
// characters “come into view” in each line by passing across the line number 0.
while (--maxLine) + 2: // +2 because maxLine is off by 1
ptr3 = 5
while (ptr -= 2) - 5:
print (*((ptr3 += 2) + 1) = *(ptr3 + 1) - 1) ? 32 : *ptr3 // 32 = space
ptr = ptr3 + 2
print 10 // newline
Begitu banyak untuk logika program. Sekarang kita perlu menerjemahkan ini ke Tidak Dapat Dibaca dan menggunakan beberapa trik golf yang lebih menarik.
Variabel selalu direferensikan secara numerik dalam Unreadable (misalnya a = 1
menjadi sesuatu seperti *(1) = 1
). Beberapa literal numerik lebih panjang dari yang lain; yang terpendek adalah 1, diikuti oleh 2, dll. Untuk menunjukkan seberapa jauh angka negatif itu, inilah angka dari -1 hingga 7:
-1 '""""""""'""""""""'""" 22
0 '""""""""'""" 13
1 '""" 4
2 '""'""" 7
3 '""'""'""" 10
4 '""'""'""'""" 13
5 '""'""'""'""'""" 16
6 '""'""'""'""'""'""" 19
7 '""'""'""'""'""'""'""" 22
Jelas, kami ingin mengalokasikan variabel # 1 ke variabel yang paling sering muncul dalam kode. Di loop sementara pertama, ini pasti mod5
, yang muncul 10 kali. Tapi kita tidak perlu mod5
lagi setelah loop sementara pertama, sehingga kita dapat mengalokasikan kembali lokasi memori yang sama ke variabel lain yang kita gunakan nanti. Ini ptr2
dan ptr3
. Sekarang variabel direferensikan 21 kali secara total. (Jika Anda mencoba menghitung sendiri jumlah kemunculannya, ingatlah untuk menghitung sekitar a++
dua kali, satu kali untuk mendapatkan nilai dan satu kali untuk menetapkannya.)
Hanya ada satu variabel lain yang bisa kita gunakan kembali; setelah kami menghitung nilai modulo, ch
tidak lagi diperlukan. up
dan dn
muncul jumlah yang sama kali, jadi tidak masalah. Merge Mari kita ch
dengan up
.
Ini menyisakan total 8 variabel unik. Kita dapat mengalokasikan variabel 0 hingga 7 dan kemudian memulai blok memori (berisi karakter dan nomor baris) pada 8. Tapi! Karena 7 panjang kode yang sama dengan −1, kita juga bisa menggunakan variabel −1 hingga 6 dan memulai blok memori pada 7. Dengan cara ini, setiap referensi ke posisi awal blok memori sedikit lebih pendek dalam kode! Ini memberi kita tugas-tugas berikut:
-1 dn
0 ← ptr or minLine?
1 mod5, ptr2, ptr3
2 curLine
3 maxLine
4 ← ptr or minLine?
5 ch, up
6 mod4
7... [data block]
Sekarang ini menjelaskan inisialisasi di bagian paling atas: itu 5 karena itu 7 (awal dari blok memori) minus 2 (kenaikan wajib dalam kondisi sementara pertama). Hal yang sama berlaku untuk dua kejadian lainnya dari 5 di loop terakhir.
Perhatikan bahwa, karena 0 dan 4 memiliki panjang kode yang sama, ptr
dan minLine
dapat dialokasikan dengan cara apa pun. ... Atau bisakah mereka?
Bagaimana dengan 2 misterius di loop kedua-terakhir sementara? Bukankah ini seharusnya 6? Kami hanya ingin mengurangi angka dalam blok data, bukan? Begitu kita mencapai 6, kita berada di luar blok data dan kita harus berhenti! Ini akan menjadi kerentanan kesalahan kegagalan buffer overflow kesalahan keamanan!
Nah, pikirkan apa yang terjadi jika kita tidak berhenti. Kami menurunkan variabel 6 dan 4. Variabel 6 adalah mod4
. Itu hanya digunakan di loop sementara pertama dan tidak lagi diperlukan di sini, jadi tidak ada salahnya dilakukan. Bagaimana dengan variabel 4? Bagaimana menurut Anda, seharusnya variabel 4 ptr
atau seharusnya minLine
? Itu benar, minLine
tidak lagi digunakan pada saat ini juga! Dengan demikian, variabel # 4 adalah minLine
dan kita dapat dengan aman mengurangi dan tidak merusak!
PEMBARUAN 1! Golfed 2199-2145 byte dengan menyadari bahwa dn
bisa juga digabung dengan mod5
, meskipun mod5
masih digunakan dalam perhitungan nilai untuk dn
! Tugas variabel baru sekarang:
0 ptr
1 mod5, dn, ptr2, ptr3
2 curLine
3 maxLine
4 minLine
5 ch, up
6 mod4
7... [data block]
PEMBARUAN 2! Ditarik dari 2145 hingga 2134 byte dengan menyadari bahwa, karena mod5
sekarang berada dalam variabel yang sama dengan dn
, yang dihitung hingga 0 dalam loop sementara, mod5
tidak perlu lagi diinisialisasi secara eksplisit ke 0.
UPDATE 3! Bermain golf dari 2134 hingga 2104 byte dengan menyadari dua hal. Pertama, meskipun ide "modulo negatif" tidak sia-sia mod5
, alasan yang sama tidak berlaku mod4
karena kami tidak pernah menguji terhadap mod4+2
dll. Oleh karena itu, mengubah mod4 ? mod4+1 : -3
untuk mod4 ? mod4-1 : 3
membawa kami ke 2110 byte. Kedua, karena mod4
selalu 0 atau 2, kita dapat menginisialisasi mod4
ke 2 bukannya 0 dan membalikkan dua terner ( mod4 ? 3 : 1
bukan mod4 ? 1 : 3
).
PEMBARUAN 4! Ditarik dari 2104 hingga 2087 byte dengan menyadari bahwa loop sementara yang menghitung nilai modulo selalu berjalan setidaknya sekali, dan dalam kasus seperti itu, Unreadable memungkinkan Anda untuk menggunakan kembali nilai pernyataan terakhir dalam ekspresi lain. Jadi, alih-alih while --ch: [...]; up = (mod5 ? mod5+1 ? [...]
sekarang kita miliki up = ((while --ch: [...]) ? mod5+1 ? [...]
(dan di dalam loop sementara itu, kita menghitung mod4
dulu, jadi itulah mod5
pernyataan terakhir).
UPDATE 5! Ditarik dari 2087 hingga 2084 byte dengan menyadari bahwa alih-alih menuliskan konstanta 32
dan 10
(spasi dan baris baru), saya dapat menyimpan angka 10 dalam variabel (sekarang tidak digunakan) variabel # 2 (sebut saja ten
). Alih-alih ptr3 = 5
kita menulis ten = (ptr3 = 5) + 5
, maka 32
menjadi ten+22
dan print 10
menjadi print ten
.