Давайте знешкоджуємо це.
Відступ:
main(_) {
_^448 && main(-~_);
putchar(--_%64
? 32 | -~7[__TIME__-_/8%8][">'txiZ^(~z?"-48] >> ";;;====~$::199"[_*2&8|_/64]/(_&2?1:8)%8&1
: 10);
}
Представляємо змінні для розв’язування цього безладу:
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
}
}
Зауважте, що -~i == i+1
через двійки-доповнення. Тому маємо
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));
}
}
Тепер зверніть увагу, що a[b]
це те самеb[a]
, і застосуйте -~ == 1+
зміни знову:
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));
}
}
Перетворення рекурсії в цикл і прокрадання в трохи більшому спрощенні:
// 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));
}
}
}
Це виводить один символ за ітерацію. Кожен 64-й символ виводить новий рядок. В іншому випадку він використовує пару таблиць даних, щоб визначити, що виводити, і ставить або символ 32 (пробіл), або символ 33 (а !
). Перша таблиця ( ">'txiZ^(~z?"
) - це набір 10 растрових зображень, що описують зовнішній вигляд кожного символу, а друга таблиця ( ";;;====~$::199"
) вибирає відповідний біт для відображення з растрової карти.
Друга таблиця
Давайте почнемо з розгляду другий таблиці int shift = ";;;====~$::199"[(i*2&8) | (i/64)];
. i/64
- номер рядка (6 до 0) і i*2&8
дорівнює 8 iff i
- 4, 5, 6 або 7 mod 8.
if((i & 2) == 0) shift /= 8; shift = shift % 8
вибирає або високу восьмеричну цифру (для i%8
= 0,1,4,5), або низьку восьмеричну цифру (для i%8
= 2,3,6,7) табличного значення. Таблиця зрушень виглядає так:
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
або в табличній формі
00005577
11775577
11775577
11665577
22773377
22773377
44443377
Зауважте, що автор використав нульовий термінатор для перших двох записів таблиці (підлий!).
Це розроблено після семисегментного дисплея з 7
пробілами s. Отже, записи в першій таблиці повинні визначати сегменти, що засвічуються.
Перша таблиця
__TIME__
є спеціальним макросом, визначеним препроцесором. Він розширюється до рядкової константи, що містить час, в який запускався препроцесор, у вигляді "HH:MM:SS"
. Зауважте, що він містить рівно 8 символів. Зауважте, що 0-9 мають значення ASCII від 48 до 57 та :
мають значення ASCII 58. Вихід становить 64 символи на рядок, так що залишається 8 символів на символ __TIME__
.
7 - i/8%8
Таким чином, індекс того, __TIME__
що зараз виводиться ( 7-
необхідний, тому що ми повторюємо i
вниз). Отже, t
характер __TIME__
виведення.
a
в кінцевому підсумку дорівнює наступному у двійковій формі, залежно від введення t
:
0 00111111
1 00101000
2 01110101
3 01111001
4 01101010
5 01011011
6 01011111
7 00101001
8 01111111
9 01111011
: 01000000
Кожне число - це растрове зображення, що описує сегменти, які висвітлюються на нашому семисегментному дисплеї. Оскільки символи всі 7-бітні ASCII, високий біт завжди очищається. Таким чином, 7
у таблиці сегментів завжди друкується як порожнє. Друга таблиця виглядає так з 7
пробілами:
000055
11 55
11 55
116655
22 33
22 33
444433
Так, наприклад, 4
є 01101010
(біти 1, 3, 5 і 6 безліч), який друкує як
----!!--
!!--!!--
!!--!!--
!!!!!!--
----!!--
----!!--
----!!--
Щоб показати, що ми дійсно розуміємо код, давайте трохи відрегулюємо висновок за допомогою цієї таблиці:
00
11 55
11 55
66
22 33
22 33
44
Це закодовано як "?;;?==? '::799\x07"
. Для мистецьких цілей ми додамо 64 до кількох символів (оскільки використовуються лише низькі 6 біт, це не вплине на вихід); це дає "?{{?}}?gg::799G"
(зауважте, що 8-й символ не використовується, тому ми можемо зробити його все, що завгодно). Введення нової таблиці у вихідний код:
main(_){_^448&&main(-~_);putchar(--_%64?32|-~7[__TIME__-_/8%8][">'txiZ^(~z?"-48]>>"?{{?}}?gg::799G"[_*2&8|_/64]/(_&2?1:8)%8&1:10);}
ми отримуємо
!! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !!
так, як ми очікували. Це не так солідний вигляд, як оригінал, що пояснює, чому автор вирішив використовувати таблицю, яку він зробив.
printf("%d", _);
до початкуmain
відбитків: pastebin.com/HHhXAYdJ