Vamos a ofuscarlo.
Sangría:
main(_) {
_^448 && main(-~_);
putchar(--_%64
? 32 | -~7[__TIME__-_/8%8][">'txiZ^(~z?"-48] >> ";;;====~$::199"[_*2&8|_/64]/(_&2?1:8)%8&1
: 10);
}
Introduciendo variables para desenredar este desastre:
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
}
}
Tenga en cuenta que -~i == i+1
debido a dos complemento. Por lo tanto, tenemos
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));
}
}
Ahora, tenga en cuenta que a[b]
es lo mismob[a]
y aplique el -~ == 1+
cambio nuevamente:
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));
}
}
Convirtiendo la recursión en un bucle y escabulléndose en un poco más de simplificación:
// 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));
}
}
}
Esto genera un carácter por iteración. Cada 64 caracteres, genera una nueva línea. De lo contrario, utiliza un par de tablas de datos para determinar qué generar y coloca el carácter 32 (un espacio) o el carácter 33 (a !
). La primera tabla ( ">'txiZ^(~z?"
) es un conjunto de 10 mapas de bits que describen la apariencia de cada carácter, y la segunda tabla ( ";;;====~$::199"
) selecciona el bit apropiado para mostrar desde el mapa de bits.
La segunda mesa
Vamos a empezar por el examen de la segunda tabla, int shift = ";;;====~$::199"[(i*2&8) | (i/64)];
. i/64
es el número de línea (6 a 0) y i*2&8
es 8 iff i
es 4, 5, 6 o 7 mod 8.
if((i & 2) == 0) shift /= 8; shift = shift % 8
selecciona el dígito octal alto (para i%8
= 0,1,4,5) o el dígito octal bajo (para i%8
= 2,3,6,7) del valor de la tabla. La tabla de turnos termina luciendo así:
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
o en forma de tabla
00005577
11775577
11775577
11665577
22773377
22773377
44443377
Tenga en cuenta que el autor utilizó el terminador nulo para las dos primeras entradas de la tabla (¡furtivo!).
Esto está diseñado después de una pantalla de siete segmentos, con 7
s como espacios en blanco. Por lo tanto, las entradas en la primera tabla deben definir los segmentos que se iluminan.
La primera mesa
__TIME__
es una macro especial definida por el preprocesador. Se expande a una constante de cadena que contiene el tiempo en que se ejecutó el preprocesador, en el formulario "HH:MM:SS"
. Observe que contiene exactamente 8 caracteres. Tenga en cuenta que 0-9 tiene valores ASCII 48 a 57 y :
tiene un valor ASCII 58. La salida es de 64 caracteres por línea, por lo que deja 8 caracteres por carácter de __TIME__
.
7 - i/8%8
es, por lo tanto, el índice __TIME__
que se está emitiendo actualmente ( 7-
es necesario porque estamos iterando i
hacia abajo). Entonces, t
es el carácter de __TIME__
ser salida.
a
termina igualando lo siguiente en binario, dependiendo de la entrada t
:
0 00111111
1 00101000
2 01110101
3 01111001
4 01101010
5 01011011
6 01011111
7 00101001
8 01111111
9 01111011
: 01000000
Cada número es un mapa de bits que describe los segmentos que se iluminan en nuestra pantalla de siete segmentos. Como los caracteres son todos ASCII de 7 bits, el bit alto siempre se borra. Por lo tanto, 7
en la tabla de segmentos siempre se imprime en blanco. La segunda tabla se ve así con la 7
s como espacios en blanco:
000055
11 55
11 55
116655
22 33
22 33
444433
Entonces, por ejemplo, 4
es 01101010
(conjunto de bits 1, 3, 5 y 6), que se imprime como
----!!--
!!--!!--
!!--!!--
!!!!!!--
----!!--
----!!--
----!!--
Para mostrar que realmente entendemos el código, ajustemos un poco la salida con esta tabla:
00
11 55
11 55
66
22 33
22 33
44
Esto está codificado como "?;;?==? '::799\x07"
. Con fines artísticos, agregaremos 64 a algunos de los caracteres (ya que solo se usan los 6 bits bajos, esto no afectará la salida); esto da "?{{?}}?gg::799G"
(tenga en cuenta que el octavo carácter no se usa, por lo que podemos convertirlo en lo que queramos). Poniendo nuestra nueva tabla en el código original:
main(_){_^448&&main(-~_);putchar(--_%64?32|-~7[__TIME__-_/8%8][">'txiZ^(~z?"-48]>>"?{{?}}?gg::799G"[_*2&8|_/64]/(_&2?1:8)%8&1:10);}
obtenemos
!! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !!
tal como lo esperábamos No es tan sólido como el original, lo que explica por qué el autor eligió usar la tabla que hizo.
printf("%d", _);
al comienzo de lasmain
impresiones: pastebin.com/HHhXAYdJ