Hãy làm xáo trộn nó.
Thụt lề:
main(_) {
_^448 && main(-~_);
putchar(--_%64
? 32 | -~7[__TIME__-_/8%8][">'txiZ^(~z?"-48] >> ";;;====~$::199"[_*2&8|_/64]/(_&2?1:8)%8&1
: 10);
}
Giới thiệu các biến để gỡ rối mớ hỗn độn này:
main(int i) {
if(i^448)
main(-~i);
if(--i % 64) {
char a = -~7[__TIME__-i/8%8][">'txiZ^(~z?"-48];
char b = a >> ";;;====~$::199"[i*2&8|i/64]/(i&2?1:8)%8;
putchar(32 | (b & 1));
} else {
putchar(10); // newline
}
}
Lưu ý rằng -~i == i+1
vì bổ sung twos. Vì vậy, chúng tôi có
main(int i) {
if(i != 448)
main(i+1);
i--;
if(i % 64 == 0) {
putchar('\n');
} else {
char a = -~7[__TIME__-i/8%8][">'txiZ^(~z?"-48];
char b = a >> ";;;====~$::199"[i*2&8|i/64]/(i&2?1:8)%8;
putchar(32 | (b & 1));
}
}
Bây giờ, lưu ý rằng a[b]
giống nhưb[a]
và áp dụng -~ == 1+
thay đổi một lần nữa:
main(int i) {
if(i != 448)
main(i+1);
i--;
if(i % 64 == 0) {
putchar('\n');
} else {
char a = (">'txiZ^(~z?"-48)[(__TIME__-i/8%8)[7]] + 1;
char b = a >> ";;;====~$::199"[(i*2&8)|i/64]/(i&2?1:8)%8;
putchar(32 | (b & 1));
}
}
Chuyển đổi đệ quy thành một vòng lặp và lén lút đơn giản hơn một chút:
// please don't pass any command-line arguments
main() {
int i;
for(i=447; i>=0; i--) {
if(i % 64 == 0) {
putchar('\n');
} else {
char t = __TIME__[7 - i/8%8];
char a = ">'txiZ^(~z?"[t - 48] + 1;
int shift = ";;;====~$::199"[(i*2&8) | (i/64)];
if((i & 2) == 0)
shift /= 8;
shift = shift % 8;
char b = a >> shift;
putchar(32 | (b & 1));
}
}
}
Điều này xuất ra một ký tự cho mỗi lần lặp. Mỗi ký tự thứ 64, nó xuất ra một dòng mới. Mặt khác, nó sử dụng một cặp bảng dữ liệu để tìm ra cái gì sẽ xuất ra và đặt ký tự 32 (khoảng trắng) hoặc ký tự 33 (a !
). Bảng đầu tiên ( ">'txiZ^(~z?"
) là một bộ gồm 10 bitmap mô tả sự xuất hiện của mỗi ký tự và bảng thứ hai ( ";;;====~$::199"
) chọn bit thích hợp để hiển thị từ bitmap.
Bảng thứ hai
Hãy bắt đầu bằng cách kiểm tra bảng thứ hai , int shift = ";;;====~$::199"[(i*2&8) | (i/64)];
. i/64
là số dòng (6 đến 0) và i*2&8
là 8 iff i
là 4, 5, 6 hoặc 7 mod 8.
if((i & 2) == 0) shift /= 8; shift = shift % 8
chọn chữ số bát phân cao (for i%8
= 0,1,4,5) hoặc chữ số bát phân thấp (for i%8
= 2,3,6,7) của giá trị bảng. Bảng ca kết thúc trông như thế này:
row col val
6 6-7 0
6 4-5 0
6 2-3 5
6 0-1 7
5 6-7 1
5 4-5 7
5 2-3 5
5 0-1 7
4 6-7 1
4 4-5 7
4 2-3 5
4 0-1 7
3 6-7 1
3 4-5 6
3 2-3 5
3 0-1 7
2 6-7 2
2 4-5 7
2 2-3 3
2 0-1 7
1 6-7 2
1 4-5 7
1 2-3 3
1 0-1 7
0 6-7 4
0 4-5 4
0 2-3 3
0 0-1 7
hoặc ở dạng bảng
00005577
11775577
11775577
11665577
22773377
22773377
44443377
Lưu ý rằng tác giả đã sử dụng bộ kết thúc null cho hai mục nhập bảng đầu tiên (lén lút!).
Điều này được thiết kế sau một màn hình bảy đoạn, với 7
s là khoảng trống. Vì vậy, các mục trong bảng đầu tiên phải xác định các phân đoạn được thắp sáng.
Bàn đầu tiên
__TIME__
là một macro đặc biệt được xác định bởi bộ tiền xử lý. Nó mở rộng thành một hằng chuỗi chứa thời gian mà bộ tiền xử lý đã chạy, ở dạng "HH:MM:SS"
. Quan sát rằng nó chứa chính xác 8 ký tự. Lưu ý rằng 0-9 có các giá trị ASCII 48 đến 57 và :
có giá trị ASCII 58. Đầu ra là 64 ký tự trên mỗi dòng, do đó để lại 8 ký tự cho mỗi ký tự __TIME__
.
7 - i/8%8
do đó, chỉ số của __TIME__
điều đó hiện đang là đầu ra (điều 7-
này là cần thiết bởi vì chúng tôi đang lặp i
xuống dưới). Vì vậy, t
là đặc tính của __TIME__
đầu ra.
a
kết thúc bằng cách sau trong nhị phân, tùy thuộc vào đầu vào t
:
0 00111111
1 00101000
2 01110101
3 01111001
4 01101010
5 01011011
6 01011111
7 00101001
8 01111111
9 01111011
: 01000000
Mỗi số là một bitmap mô tả các phân đoạn được thắp sáng trong màn hình bảy phân đoạn của chúng tôi. Vì các ký tự đều là ASCII 7 bit, bit cao luôn bị xóa. Vì vậy, 7
trong bảng phân khúc luôn in dưới dạng trống. Bảng thứ hai trông như thế này với 7
s là khoảng trống:
000055
11 55
11 55
116655
22 33
22 33
444433
Vì vậy, ví dụ, 4
là 01101010
(các bit 1, 3, 5 và 6), in ra như
----!!--
!!--!!--
!!--!!--
!!!!!!--
----!!--
----!!--
----!!--
Để cho thấy chúng tôi thực sự hiểu mã, hãy điều chỉnh đầu ra một chút với bảng này:
00
11 55
11 55
66
22 33
22 33
44
Điều này được mã hóa như "?;;?==? '::799\x07"
. Đối với mục đích nghệ thuật, chúng tôi sẽ thêm 64 vào một vài ký tự (vì chỉ sử dụng 6 bit thấp, điều này sẽ không ảnh hưởng đến đầu ra); điều này mang lại "?{{?}}?gg::799G"
(lưu ý rằng ký tự thứ 8 không được sử dụng, vì vậy chúng ta thực sự có thể làm cho nó bất cứ điều gì chúng ta muốn). Đặt bảng mới của chúng tôi vào mã gốc:
main(_){_^448&&main(-~_);putchar(--_%64?32|-~7[__TIME__-_/8%8][">'txiZ^(~z?"-48]>>"?{{?}}?gg::799G"[_*2&8|_/64]/(_&2?1:8)%8&1:10);}
chúng tôi nhận được
!! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !!
đúng như chúng ta mong đợi Nó không có vẻ ngoài chắc chắn như bản gốc, điều này giải thích tại sao tác giả chọn sử dụng bảng mà anh ta đã làm.
printf("%d", _);
vào phần đầu củamain
bản in: pastebin.com/HHhXAYdJ