Hitungan byte mengasumsikan penyandian ISO 8859-1.
+%`\B
¶$`:
1
Cobalah online!
Solusi alternatif:
+1`\B
:$`:
1
Penjelasan
Ini mungkin akan lebih mudah dijelaskan berdasarkan versi saya yang lama, kurang golf, dan kemudian menunjukkan bagaimana saya mempersingkatnya. Saya dulu mengonversi biner menjadi desimal seperti ini:
^
,
+`,(.)
$`$1,
1
Satu-satunya cara yang masuk akal untuk membangun angka desimal di Retina adalah dengan menghitung banyak hal (karena Retina memiliki beberapa fitur yang memungkinkannya mencetak angka desimal yang mewakili jumlah). Jadi sebenarnya satu-satunya pendekatan yang mungkin adalah mengubah biner menjadi unary, dan kemudian menghitung jumlah digit unary. Baris terakhir menghitung, jadi yang pertama mengkonversi biner ke unary.
Bagaimana kita melakukannya? Secara umum, untuk mengkonversi dari daftar bit ke integer, kami menginisialisasi hasilnya 0
dan kemudian pergi melalui bit dari yang paling signifikan, menggandakan nilai yang sudah kami miliki dan menambahkan bit saat ini. Misalnya, jika angka binernya adalah 1011
, kami akan menghitung:
(((0 * 2 + 1) * 2 + 0) * 2 + 1) * 2 + 1 = 11
^ ^ ^ ^
Di mana saya telah menandai bit individu untuk kejelasan.
Trik untuk melakukan ini di unary adalah a) bahwa menggandakan berarti mengulangi angka dan b) karena kita menghitung 1
s pada akhirnya, kita bahkan tidak perlu membedakan antara 0
s dan 1
s dalam proses. Ini akan menjadi lebih jelas dalam sedetik.
Apa yang dilakukan oleh program adalah bahwa ia pertama kali menambahkan koma ke awal sebagai penanda untuk berapa banyak input yang sudah kami proses:
^
,
Di sebelah kiri marker, kita akan memiliki nilai yang kita akumulasikan (yang diinisialisasi dengan benar ke representasi nol unary), dan kanan nilai akan menjadi bit berikutnya untuk diproses. Sekarang kami menerapkan substitusi berikut dalam satu lingkaran:
,(.)
$`$1,
Hanya dengan melihat ,(.)
dan $1,
, ini menggerakkan marker sedikit ke kanan setiap kali. Tapi kami juga menyisipkan $`
, yang merupakan segalanya di depan marker, yaitu nilai saat ini, yang kami gandakan. Berikut adalah langkah-langkah individual saat memproses input 1011
, di mana saya telah menandai hasil dari menyisipkan di $`
atas setiap baris (kosong untuk langkah pertama):
,1011
1,011
_
110,11
___
1101101,1
_______
110110111011011,
Anda akan melihat bahwa kami telah mempertahankan dan menggandakan nol bersama dengan yang lainnya, tetapi karena kami mengabaikannya pada akhirnya, tidak masalah seberapa sering kami menggandakannya, selama jumlah 1
s adalah benar. Jika Anda menghitungnya, ada beberapa 11
, hanya yang kita butuhkan.
Sehingga menyisakan pertanyaan bagaimana cara memainkan golf ini hingga 12 byte. Bagian termahal dari versi 18-byte adalah harus menggunakan marker. Tujuannya adalah untuk menyingkirkan itu. Kami benar-benar ingin menggandakan awalan setiap bit, jadi ide pertama mungkin ini:
.
$`$&
Masalahnya adalah bahwa pergantian ini terjadi secara bersamaan, jadi bit pertama tidak menjadi dua kali lipat untuk setiap bit, tetapi hanya akan disalin sekali setiap kali. Untuk input yang 1011
akan kami dapatkan (menandai yang dimasukkan $`
):
_ __ ___
1101011011
Kita masih perlu memproses input secara rekursif sehingga awalan pertama yang digandakan digandakan lagi oleh yang kedua dan seterusnya. Satu ide adalah menyisipkan spidol di mana-mana dan berulang kali menggantinya dengan awalan:
\B
,
+%`,
¶$`
Setelah mengganti setiap penanda dengan awalan untuk pertama kalinya, kita perlu mengingat di mana awal input itu, jadi kami juga memasukkan umpan baris dan menggunakan %
opsi untuk memastikan bahwa berikutnya $`
hanya mengambil hal-hal yang sesuai dengan umpan baris terdekat.
Ini berfungsi, tetapi masih terlalu lama (16 byte saat menghitung 1
s di akhir). Bagaimana kalau kita membalikkan keadaan? Tempat-tempat di mana kita ingin menyisipkan marker diidentifikasi oleh \B
(posisi di antara dua digit). Mengapa kita tidak memasukkan saja awalan ke posisi itu? Ini hampir berhasil, tetapi perbedaannya adalah bahwa dalam solusi sebelumnya, kami benar-benar menghapus satu penanda di setiap substitusi, dan itu penting untuk membuat proses berakhir. Namun, \B
bukan karakter tetapi hanya posisi, jadi tidak ada yang dihapus. Namun kita dapat menghentikannya\B
dari mencocokkan dengan memasukkan karakter non-digit ke tempat ini. Itu mengubah batas non-kata menjadi batas kata, yang setara dengan menghapus karakter penanda sebelumnya. Dan itulah yang dilakukan solusi 12-byte:
+%`\B
¶$`:
Hanya untuk kelengkapan, berikut adalah langkah-langkah pemrosesan 1011
, dengan baris kosong setelah setiap langkah:
1
1:0
10:1
101:1
1
1:0
1
1:0:1
1
1:0
10:1:1
1
1:0
1
1:0:1
1
1:0
1
1:0:1:1
Sekali lagi, Anda akan menemukan bahwa hasil terakhir mengandung tepat 11 1
detik.
Sebagai latihan untuk pembaca, dapatkah Anda melihat bagaimana ini secara umum dengan mudah ke pangkalan lain (untuk beberapa byte tambahan per kenaikan di pangkalan)?