難読化を解除しましょう。
インデント:
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
2の補数のために注意してください。したがって、
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));
}
}
}
これにより、反復ごとに1文字が出力されます。64文字ごとに、改行を出力します。それ以外の場合は、データテーブルのペアを使用して何を出力するかを判断し、文字32(スペース)または文字33(a !
)のいずれかを配置します。最初のテーブル(">'txiZ^(~z?"
)は、各文字の外観を説明する10個のビットマップのセットであり、2番目のテーブル(";;;====~$::199"
)は、ビットマップから表示する適切なビットを選択します。
2番目のテーブル
2番目のテーブルを調べることから始めましょうint shift = ";;;====~$::199"[(i*2&8) | (i/64)];
。i/64
は行番号(6から0)であり、4、5、6、またはi*2&8
7mod8の場合i
は8です。
if((i & 2) == 0) shift /= 8; shift = shift % 8
テーブル値の上位8進数(i%8
= 0,1,4,5の場合)または下位8進数(= 2,3,6,7の場合)のいずれかを選択i%8
します。シフトテーブルは次のようになります。
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
作成者が最初の2つのテーブルエントリにヌルターミネータを使用したことに注意してください(卑劣です!)。
7
これは、 sをブランクとして、7セグメントディスプレイを基に設計されています。したがって、最初のテーブルのエントリは、点灯するセグメントを定義する必要があります。
最初のテーブル
__TIME__
プリプロセッサによって定義された特別なマクロです。これは、プリプロセッサが実行された時刻を含む文字列定数に展開されます。形式は"HH:MM:SS"
です。正確に8文字含まれていることを確認してください。0〜9:
のASCII値は48〜57で、ASCII値は58であることに注意してください。出力は1行あたり64文字であるため、。の1文字あたり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セグメントディスプレイで点灯しているセグメントを説明するビットマップです。文字はすべて7ビットASCIIであるため、上位ビットは常にクリアされます。したがって、7
セグメントテーブルでは常に空白として印刷されます。2番目のテーブルは、7
sをブランクとして次のようになります。
000055
11 55
11 55
116655
22 33
22 33
444433
したがって、たとえば、(ビット1、3、5、および6セット)は、次のように出力されます4
。01101010
----!!--
!!--!!--
!!--!!--
!!!!!!--
----!!--
----!!--
----!!--
コードを本当に理解していることを示すために、次の表を使用して出力を少し調整してみましょう。
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);}
我々が得る
!! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !!
思った通り。それはオリジナルほど堅実に見えません、それは著者が彼がしたテーブルを使うことを選んだ理由を説明します。