Давайте де-запутать это.
Отступ:
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, если 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
пробелами s:
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