C, 59 byte
i;f(char*s){while(*s&3?*s&9||(i+=i+*s%5):putchar(i),*s++);}
Angka ajaib, angka ajaib di mana-mana!
(Juga, C lebih pendek dari Python, JS, PHP, dan Ruby? Belum pernah terjadi!)
Ini adalah fungsi yang mengambil string sebagai input dan output ke STDOUT.
Panduan
Struktur dasarnya adalah:
i; // initialize an integer i to 0
f(char*s){
while(...); // run the stuff inside until it becomes 0
}
Di sini, "barang-barang di dalam" adalah sekelompok kode diikuti oleh ,*s++
, di mana koma operater hanya mengembalikan nilai argumen kedua. Oleh karena itu, ini akan dijalankan melalui string dan diatur *s
ke setiap karakter, termasuk byte NUL yang tertinggal (karena postfix ++
mengembalikan nilai sebelumnya), sebelum keluar.
Mari kita lihat sisanya:
*s&3?*s&9||(i+=i+*s%5):putchar(i)
Mengupas bagian luar dan hubungan arus pendek ||
, ini dapat diperluas
if (*s & 3) {
if (!(*s & 9)) {
i += i + *s % 5;
}
} else {
putchar(i);
}
Dari mana angka-angka ajaib ini berasal? Berikut adalah representasi biner dari semua karakter yang terlibat:
F 70 01000110
B 66 01000010
i 105 01101001
z 122 01111010
u 117 01110101
32 00100000
\0 0 00000000
Pertama, kita perlu memisahkan ruang dan NUL dari karakter lainnya. Cara algoritme ini bekerja, ia menyimpan akumulator dari angka "saat ini", dan mencetaknya setiap kali mencapai ruang atau akhir string (yaitu '\0'
). Dengan memperhatikan itu ' '
dan '\0'
merupakan satu-satunya karakter yang tidak memiliki salah satu dari dua bit paling tidak signifikan yang ditetapkan, kita dapat bitwise DAN karakter dengan 0b11
untuk mendapatkan nol jika karakter tersebut adalah spasi atau NUL dan bukan nol sebaliknya.
Menggali lebih dalam, di cabang "jika" pertama, kita sekarang memiliki karakter yang salah satunya FBizu
. Saya hanya memilih untuk memperbarui akumulator pada F
s dan B
s, jadi saya perlu beberapa cara untuk menyaring izu
s. Secara mudah, F
dan B
keduanya hanya memiliki set bit paling signifikan kedua, ketiga, atau ketujuh yang ditetapkan, dan semua angka lainnya memiliki setidaknya satu set bit lainnya. Faktanya, mereka semua memiliki bit pertama atau keempat yang paling tidak signifikan. Oleh karena itu, kita dapat bitwise AND dengan 0b00001001
, yaitu 9, yang akan menghasilkan 0 untuk F
dan B
dan bukan nol sebaliknya.
Setelah kita menentukan bahwa kita memiliki F
atau B
, kita dapat memetakannya ke 0
dan 1
masing - masing dengan mengambil modulus 5 mereka, karena F
ada 70
dan B
sedang 66
. Lalu potongannya
i += i + *s % 5;
hanyalah cara pepatah golf
i = (i * 2) + (*s % 5);
yang juga dapat dinyatakan sebagai
i = (i << 1) | (*s % 5);
yang memasukkan bit baru pada posisi paling tidak signifikan dan menggeser yang lainnya lebih dari 1.
"Tapi tunggu!" Anda mungkin protes. "Setelah Anda mencetak i
, kapan itu akan kembali ke 0?" Nah, putchar
melemparkan argumennya ke sebuah unsigned char
, yang kebetulan berukuran 8 bit. Itu berarti semuanya melewati bit ke-8 yang paling signifikan (yaitu sampah dari iterasi sebelumnya) dibuang, dan kita tidak perlu khawatir tentang hal itu.
Terima kasih kepada @ETHproductions karena menyarankan untuk mengganti 57
dengan 9
, menghemat satu byte!