C, 59 byte
i;f(char*s){while(*s&3?*s&9||(i+=i+*s%5):putchar(i),*s++);}
Số ma thuật, số ma thuật ở khắp mọi nơi!
(Ngoài ra, C ngắn hơn Python, JS, PHP và Ruby? Chưa từng thấy!)
Đây là một hàm lấy một chuỗi làm đầu vào và đầu ra cho STDOUT.
Hướng dẫn
Cấu trúc cơ bản là:
i; // initialize an integer i to 0
f(char*s){
while(...); // run the stuff inside until it becomes 0
}
Ở đây, "nội dung bên trong" là một loạt các mã theo sau ,*s++
, trong đó toán tử dấu phẩy chỉ trả về giá trị của đối số thứ hai của nó. Do đó, điều này sẽ chạy qua chuỗi và được đặt *s
thành mọi ký tự, bao gồm byte NUL trailing (vì postfix ++
trả về giá trị trước đó), trước khi thoát.
Hãy xem phần còn lại:
*s&3?*s&9||(i+=i+*s%5):putchar(i)
Lột bỏ ternary và ngắn mạch ||
, điều này có thể được mở rộng để
if (*s & 3) {
if (!(*s & 9)) {
i += i + *s % 5;
}
} else {
putchar(i);
}
Những con số ma thuật này đến từ đâu? Dưới đây là các biểu diễn nhị phân của tất cả các nhân vật liên quan:
F 70 01000110
B 66 01000010
i 105 01101001
z 122 01111010
u 117 01110101
32 00100000
\0 0 00000000
Đầu tiên, chúng ta cần tách không gian và NUL khỏi các nhân vật còn lại. Cách thuật toán này hoạt động, nó giữ một bộ tích lũy của số "hiện tại" và in nó bất cứ khi nào nó đạt đến một khoảng trắng hoặc cuối chuỗi (tức là '\0'
). Bằng cách nhận thấy rằng ' '
và '\0'
là các ký tự duy nhất không có bất kỳ bit nào trong hai bit có ý nghĩa nhỏ nhất, chúng ta có thể bit bit VÀ ký tự bằng 0b11
0 nếu ký tự là khoảng trắng hoặc NUL và khác không.
Đào sâu hơn, trong nhánh "nếu" đầu tiên, bây giờ chúng ta có một nhân vật là một trong số đó FBizu
. Tôi đã chọn chỉ cập nhật bộ tích lũy trên F
s và B
s, vì vậy tôi cần một số cách để lọc ra izu
s. Thuận tiện F
và B
cả hai chỉ có các bit quan trọng thứ hai, thứ ba hoặc thứ bảy, và tất cả các số khác có ít nhất một bit khác được đặt. Trong thực tế, tất cả chúng đều có bit đầu tiên hoặc thứ tư ít quan trọng nhất. Do đó, chúng ta có thể Bitwise và với 0b00001001
, đó là 9, mà sẽ mang lại 0 cho F
và B
và khác không khác.
Khi chúng tôi đã xác định rằng chúng tôi có một F
hoặc B
, chúng tôi có thể ánh xạ chúng tới 0
và 1
tương ứng bằng cách lấy mô đun 5 của chúng, bởi vì F
nó đã 70
và B
đang tồn tại 66
. Sau đó là đoạn trích
i += i + *s % 5;
chỉ là một cách nói golf
i = (i * 2) + (*s % 5);
cũng có thể được thể hiện như
i = (i << 1) | (*s % 5);
trong đó chèn bit mới vào vị trí ít quan trọng nhất và dịch chuyển mọi thứ khác trên 1.
"Nhưng đợi đã!" bạn có thể phản đối "Sau khi bạn in i
, khi nào nó được đặt lại về 0?" Chà, putchar
đưa đối số của nó thành một unsigned char
, có kích thước tương đương 8 bit. Điều đó có nghĩa là mọi thứ vượt qua bit thứ 8 ít nhất (nghĩa là rác từ các lần lặp trước) bị vứt đi và chúng ta không cần phải lo lắng về điều đó.
Cảm ơn @ETHproductions đã đề xuất thay thế 57
bằng 9
, tiết kiệm một byte!